import { useEffect } from 'react'; import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer'; 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 { TASK_STATUS_LABELS, TASK_STATUS_STYLES } from '@renderer/utils/memberHelpers'; import { formatDistanceToNow } from 'date-fns'; import { ArrowLeftFromLine, ArrowRightFromLine, Clock, FileText, PenLine, User, } from 'lucide-react'; import { TaskCommentsSection } from './TaskCommentsSection'; import type { KanbanTaskState, ResolvedTeamMember, TeamTask } from '@shared/types'; interface TaskDetailDialogProps { open: boolean; task: TeamTask | 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?.id, currentTask?.comments]); const handleDependencyClick = (taskId: string): void => { onClose(); onScrollToTask?.(taskId); }; if (!currentTask) { return ( !v && onClose()}> Task not found ); } const status = currentTask.status; const statusStyle = TASK_STATUS_STYLES[status]; const statusLabel = TASK_STATUS_LABELS[status]; const blockedByIds = currentTask.blockedBy?.filter((id) => id.length > 0) ?? []; const blocksIds = currentTask.blocks?.filter((id) => id.length > 0) ?? []; 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 */}
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} {/* Review info */} {kanbanTaskState ? (
{kanbanTaskState.reviewer ? ( Reviewer: {kanbanTaskState.reviewer} ) : null} {kanbanTaskState.errorDescription ? ( {kanbanTaskState.errorDescription} ) : null}
) : null} {/* Comments */} {/* Separator */}
{/* Session Logs — sessions that reference this task */}

Execution Logs

); };