import { useState, useEffect } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { useDialog } from "../context/DialogContext"; import { useCompany } from "../context/CompanyContext"; import { issuesApi } from "../api/issues"; import { projectsApi } from "../api/projects"; import { agentsApi } from "../api/agents"; import { queryKeys } from "../lib/queryKeys"; import { Dialog, DialogContent, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger, } from "@/components/ui/popover"; import { Maximize2, Minimize2, MoreHorizontal, CircleDot, Minus, ArrowUp, ArrowDown, AlertTriangle, User, Hexagon, Tag, Calendar, } from "lucide-react"; import { cn } from "../lib/utils"; import type { Project, Agent } from "@paperclip/shared"; const statuses = [ { value: "backlog", label: "Backlog", color: "text-muted-foreground" }, { value: "todo", label: "Todo", color: "text-blue-400" }, { value: "in_progress", label: "In Progress", color: "text-yellow-400" }, { value: "in_review", label: "In Review", color: "text-violet-400" }, { value: "done", label: "Done", color: "text-green-400" }, ]; const priorities = [ { value: "critical", label: "Critical", icon: AlertTriangle, color: "text-red-400" }, { value: "high", label: "High", icon: ArrowUp, color: "text-orange-400" }, { value: "medium", label: "Medium", icon: Minus, color: "text-yellow-400" }, { value: "low", label: "Low", icon: ArrowDown, color: "text-blue-400" }, ]; export function NewIssueDialog() { const { newIssueOpen, newIssueDefaults, closeNewIssue } = useDialog(); const { selectedCompanyId, selectedCompany } = useCompany(); const queryClient = useQueryClient(); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [status, setStatus] = useState("todo"); const [priority, setPriority] = useState(""); const [assigneeId, setAssigneeId] = useState(""); const [projectId, setProjectId] = useState(""); const [expanded, setExpanded] = useState(false); // Popover states const [statusOpen, setStatusOpen] = useState(false); const [priorityOpen, setPriorityOpen] = useState(false); const [assigneeOpen, setAssigneeOpen] = useState(false); const [projectOpen, setProjectOpen] = useState(false); const [moreOpen, setMoreOpen] = useState(false); const { data: agents } = useQuery({ queryKey: queryKeys.agents.list(selectedCompanyId!), queryFn: () => agentsApi.list(selectedCompanyId!), enabled: !!selectedCompanyId && newIssueOpen, }); const { data: projects } = useQuery({ queryKey: queryKeys.projects.list(selectedCompanyId!), queryFn: () => projectsApi.list(selectedCompanyId!), enabled: !!selectedCompanyId && newIssueOpen, }); const createIssue = useMutation({ mutationFn: (data: Record) => issuesApi.create(selectedCompanyId!, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.issues.list(selectedCompanyId!) }); reset(); closeNewIssue(); }, }); useEffect(() => { if (newIssueOpen) { setStatus(newIssueDefaults.status ?? "todo"); setPriority(newIssueDefaults.priority ?? ""); setProjectId(newIssueDefaults.projectId ?? ""); } }, [newIssueOpen, newIssueDefaults]); function reset() { setTitle(""); setDescription(""); setStatus("todo"); setPriority(""); setAssigneeId(""); setProjectId(""); setExpanded(false); } function handleSubmit() { if (!selectedCompanyId || !title.trim()) return; createIssue.mutate({ title: title.trim(), description: description.trim() || undefined, status, priority: priority || "medium", ...(assigneeId ? { assigneeAgentId: assigneeId } : {}), ...(projectId ? { projectId } : {}), }); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); handleSubmit(); } } const currentStatus = statuses.find((s) => s.value === status) ?? statuses[1]!; const currentPriority = priorities.find((p) => p.value === priority); const currentAssignee = (agents ?? []).find((a) => a.id === assigneeId); const currentProject = (projects ?? []).find((p) => p.id === projectId); return ( { if (!open) { reset(); closeNewIssue(); } }} > {/* Header bar */}
{selectedCompany && ( {selectedCompany.name.slice(0, 3).toUpperCase()} )} New issue
{/* Title */}
setTitle(e.target.value)} autoFocus />
{/* Description */}