import { useEffect } from 'react'; import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer'; import { CollapsibleTeamSection } from '@renderer/components/team/CollapsibleTeamSection'; import { MemberLogsTab } from '@renderer/components/team/members/MemberLogsTab'; import { Badge } from '@renderer/components/ui/badge'; import { Button } from '@renderer/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@renderer/components/ui/dialog'; import { markAsRead } from '@renderer/services/commentReadStorage'; import { KANBAN_COLUMN_DISPLAY, TASK_STATUS_LABELS, TASK_STATUS_STYLES, } from '@renderer/utils/memberHelpers'; import { formatDistanceToNow } from 'date-fns'; import { ArrowLeftFromLine, ArrowRightFromLine, Clock, Link2, PenLine, User } from 'lucide-react'; import { TaskCommentsSection } from './TaskCommentsSection'; import type { KanbanTaskState, ResolvedTeamMember, TeamTaskWithKanban } from '@shared/types'; interface TaskDetailDialogProps { open: boolean; task: TeamTaskWithKanban | null; teamName: string; kanbanTaskState?: KanbanTaskState; taskMap: Map; members: ResolvedTeamMember[]; onClose: () => void; onScrollToTask?: (taskId: string) => void; } export const TaskDetailDialog = ({ open, task, teamName, kanbanTaskState, taskMap, members, onClose, onScrollToTask, }: TaskDetailDialogProps): React.JSX.Element => { const currentTask = task ? (taskMap.get(task.id) ?? task) : null; useEffect(() => { if (!open || !currentTask) return; const comments = currentTask.comments ?? []; if (comments.length === 0) return; const latest = Math.max(...comments.map((c) => new Date(c.createdAt).getTime())); if (latest > 0) markAsRead(teamName, currentTask.id, latest); }, [open, teamName, currentTask]); const handleDependencyClick = (taskId: string): void => { onClose(); onScrollToTask?.(taskId); }; if (!currentTask) { return ( !v && onClose()}> Task not found ); } const kanbanColumn = kanbanTaskState?.column ?? currentTask.kanbanColumn; const status = currentTask.status; const statusStyle = kanbanColumn && KANBAN_COLUMN_DISPLAY[kanbanColumn] ? { bg: KANBAN_COLUMN_DISPLAY[kanbanColumn].bg, text: KANBAN_COLUMN_DISPLAY[kanbanColumn].text, } : TASK_STATUS_STYLES[status]; const statusLabel = kanbanColumn && KANBAN_COLUMN_DISPLAY[kanbanColumn] ? KANBAN_COLUMN_DISPLAY[kanbanColumn].label : TASK_STATUS_LABELS[status]; const blockedByIds = currentTask.blockedBy?.filter((id) => id.length > 0) ?? []; const blocksIds = currentTask.blocks?.filter((id) => id.length > 0) ?? []; const relatedIds = (currentTask.related ?? []).filter( (id) => id.length > 0 && id !== currentTask.id ); const relatedByIds = Array.from(taskMap.values()) .filter( (t) => t.id !== currentTask.id && Array.isArray(t.related) && t.related.includes(currentTask.id) ) .map((t) => t.id); return ( !v && onClose()}>
#{currentTask.id} {statusLabel}
{currentTask.subject} {currentTask.activeForm ? ( {currentTask.activeForm} ) : null}
{/* Metadata */}
{currentTask.owner ?? '\u2014'}
{currentTask.createdBy ? (
{currentTask.createdBy}
) : null} {currentTask.createdAt ? (() => { const date = new Date(currentTask.createdAt); return isNaN(date.getTime()) ? null : (
{formatDistanceToNow(date, { addSuffix: true })}
); })() : null}
{/* Description */} {currentTask.description ? (
) : (

No description

)}
{/* Dependencies */} {blockedByIds.length > 0 ? (
Blocked by {blockedByIds.map((id) => { const depTask = taskMap.get(id); const isCompleted = depTask?.status === 'completed'; return ( ); })}
) : null} {blocksIds.length > 0 ? (
Blocks {blocksIds.map((id) => { const depTask = taskMap.get(id); const isCompleted = depTask?.status === 'completed'; return ( ); })}
) : null} {/* Related tasks (explicit) */} {relatedIds.length > 0 || relatedByIds.length > 0 ? (
Related tasks
{relatedIds.length > 0 ? (
Links {relatedIds.map((id) => { const depTask = taskMap.get(id); return ( ); })}
) : null} {relatedByIds.length > 0 ? (
Linked from {relatedByIds.map((id) => { const depTask = taskMap.get(id); return ( ); })}
) : null}
) : null} {/* Review info */} {kanbanTaskState ? (
{kanbanTaskState.reviewer ? ( Reviewer: {kanbanTaskState.reviewer} ) : null} {kanbanTaskState.errorDescription ? ( {kanbanTaskState.errorDescription} ) : null}
) : null} {/* Comments */} 0 ? (currentTask.comments?.length ?? 0) : undefined } defaultOpen > {/* Execution Logs — sessions that reference this task */}
); };