import { useRef, useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { GOAL_STATUSES, GOAL_LEVELS } from "@paperclipai/shared"; import { useDialog } from "../context/DialogContext"; import { useCompany } from "../context/CompanyContext"; import { goalsApi } from "../api/goals"; import { assetsApi } from "../api/assets"; 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, Target, Layers, } from "lucide-react"; import { cn } from "../lib/utils"; import { MarkdownEditor, type MarkdownEditorRef } from "./MarkdownEditor"; import { StatusBadge } from "./StatusBadge"; const levelLabels: Record = { company: "Company", team: "Team", agent: "Agent", task: "Task", }; export function NewGoalDialog() { const { newGoalOpen, newGoalDefaults, closeNewGoal } = useDialog(); const { selectedCompanyId, selectedCompany } = useCompany(); const queryClient = useQueryClient(); const [title, setTitle] = useState(""); const [description, setDescription] = useState(""); const [status, setStatus] = useState("planned"); const [level, setLevel] = useState("task"); const [parentId, setParentId] = useState(""); const [expanded, setExpanded] = useState(false); const [statusOpen, setStatusOpen] = useState(false); const [levelOpen, setLevelOpen] = useState(false); const [parentOpen, setParentOpen] = useState(false); const descriptionEditorRef = useRef(null); // Apply defaults when dialog opens const appliedParentId = parentId || newGoalDefaults.parentId || ""; const { data: goals } = useQuery({ queryKey: queryKeys.goals.list(selectedCompanyId!), queryFn: () => goalsApi.list(selectedCompanyId!), enabled: !!selectedCompanyId && newGoalOpen, }); const createGoal = useMutation({ mutationFn: (data: Record) => goalsApi.create(selectedCompanyId!, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: queryKeys.goals.list(selectedCompanyId!) }); reset(); closeNewGoal(); }, }); const uploadDescriptionImage = useMutation({ mutationFn: async (file: File) => { if (!selectedCompanyId) throw new Error("No company selected"); return assetsApi.uploadImage(selectedCompanyId, file, "goals/drafts"); }, }); function reset() { setTitle(""); setDescription(""); setStatus("planned"); setLevel("task"); setParentId(""); setExpanded(false); } function handleSubmit() { if (!selectedCompanyId || !title.trim()) return; createGoal.mutate({ title: title.trim(), description: description.trim() || undefined, status, level, ...(appliedParentId ? { parentId: appliedParentId } : {}), }); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) { e.preventDefault(); handleSubmit(); } } const currentParent = (goals ?? []).find((g) => g.id === appliedParentId); return ( { if (!open) { reset(); closeNewGoal(); } }} > {/* Header */}
{selectedCompany && ( {selectedCompany.name.slice(0, 3).toUpperCase()} )} {newGoalDefaults.parentId ? "New sub-goal" : "New goal"}
{/* Title */}
setTitle(e.target.value)} onKeyDown={(e) => { if (e.key === "Tab" && !e.shiftKey) { e.preventDefault(); descriptionEditorRef.current?.focus(); } }} autoFocus />
{/* Description */}
{ const asset = await uploadDescriptionImage.mutateAsync(file); return asset.contentPath; }} />
{/* Property chips */}
{/* Status */} {GOAL_STATUSES.map((s) => ( ))} {/* Level */} {GOAL_LEVELS.map((l) => ( ))} {/* Parent goal */} {(goals ?? []).map((g) => ( ))}
{/* Footer */}
); }