import { useEffect, useMemo, useState } from 'react'; import { AlertCircle, ArrowRight, CheckCircle, ChevronDown, ChevronRight, Circle, Clock, Copy, Edit, Pause, Save, X, } from 'lucide-react'; import { cn } from '../../../lib/utils'; import { copyTextToClipboard } from '../../../utils/clipboard'; import { api } from '../../../utils/api'; import { useTaskMaster } from '../context/TaskMasterContext'; import type { TaskId, TaskMasterTask, TaskReference } from '../types'; type TaskDetailModalProps = { task: TaskMasterTask | null; isOpen?: boolean; className?: string; onClose: () => void; onEdit?: ((task: TaskMasterTask) => void) | null; onStatusChange?: ((taskId: TaskId, status: string) => void) | null; onTaskClick?: ((task: TaskReference) => void) | null; }; const STATUS_OPTIONS = [ { value: 'pending', label: 'Pending' }, { value: 'in-progress', label: 'In Progress' }, { value: 'review', label: 'Review' }, { value: 'done', label: 'Done' }, { value: 'deferred', label: 'Deferred' }, { value: 'cancelled', label: 'Cancelled' }, ]; function getStatusIcon(status?: string) { if (status === 'done') return CheckCircle; if (status === 'in-progress') return Clock; if (status === 'review') return AlertCircle; if (status === 'deferred') return Pause; if (status === 'cancelled') return X; return Circle; } function getPriorityBadgeClass(priority?: string): string { if (priority === 'high') return 'text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-950'; if (priority === 'medium') return 'text-yellow-600 dark:text-yellow-400 bg-yellow-50 dark:bg-yellow-950'; if (priority === 'low') return 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-950'; return 'text-gray-600 dark:text-gray-400 bg-gray-50 dark:bg-gray-800'; } export default function TaskDetailModal({ task, isOpen = true, className = '', onClose, onEdit = null, onStatusChange = null, onTaskClick = null, }: TaskDetailModalProps) { const { currentProject, refreshTasks } = useTaskMaster(); const [isEditMode, setIsEditMode] = useState(false); const [isSaving, setIsSaving] = useState(false); const [showDetails, setShowDetails] = useState(false); const [showTestStrategy, setShowTestStrategy] = useState(false); const [editableTask, setEditableTask] = useState(task); useEffect(() => { setEditableTask(task); setIsEditMode(false); }, [task]); const StatusIcon = useMemo(() => getStatusIcon(task?.status), [task?.status]); if (!isOpen || !task || !editableTask) { return null; } const handleSaveChanges = async () => { if (!currentProject?.name) { return; } const updates: Record = {}; if (editableTask.title !== task.title) { updates.title = editableTask.title; } if (editableTask.description !== task.description) { updates.description = editableTask.description ?? ''; } if (editableTask.details !== task.details) { updates.details = editableTask.details ?? ''; } if (Object.keys(updates).length === 0) { setIsEditMode(false); return; } setIsSaving(true); try { const response = await api.taskmaster.updateTask(currentProject.name, task.id, updates); if (!response.ok) { const errorPayload = (await response.json()) as { message?: string }; throw new Error(errorPayload.message ?? 'Failed to update task'); } setIsEditMode(false); await refreshTasks(); onEdit?.(editableTask); } catch (error) { console.error('Failed to save task changes:', error); alert(error instanceof Error ? error.message : 'Failed to update task'); } finally { setIsSaving(false); } }; const handleStatusSelect = async (nextStatus: string) => { if (!currentProject?.name || nextStatus === task.status) { return; } try { const response = await api.taskmaster.updateTask(currentProject.name, task.id, { status: nextStatus }); if (!response.ok) { const errorPayload = (await response.json()) as { message?: string }; throw new Error(errorPayload.message ?? 'Failed to update task status'); } await refreshTasks(); onStatusChange?.(task.id, nextStatus); } catch (error) { console.error('Failed to update task status:', error); alert(error instanceof Error ? error.message : 'Failed to update task status'); } }; return (
{isEditMode ? ( setEditableTask({ ...editableTask, title: event.target.value })} className="w-full text-lg font-semibold bg-transparent border-b-2 border-blue-500 focus:outline-none text-gray-900 dark:text-white" /> ) : (

{task.title}

)}
{isEditMode ? ( <> ) : ( )}
{task.priority ?? 'Not set'}
{Array.isArray(task.dependencies) && task.dependencies.length > 0 ? (
{task.dependencies.map((dependency) => ( ))}
) : ( No dependencies )}
{isEditMode ? (