import type { Task, TaskStatus, TaskPriority } from "../lib/types"; const priorityColors: Record = { critical: "bg-red-500 text-white", high: "bg-orange-500 text-white", medium: "bg-blue-500 text-white", low: "bg-gray-400 text-white", }; const sourceColors: Record = { donovan: "bg-purple-100 text-purple-800", david: "bg-green-100 text-green-800", hammer: "bg-yellow-100 text-yellow-800", heartbeat: "bg-pink-100 text-pink-800", cron: "bg-indigo-100 text-indigo-800", other: "bg-gray-100 text-gray-800", }; const statusActions: Record = { active: [ { label: "⏸ Pause", next: "queued" }, { label: "✅ Complete", next: "completed" }, ], queued: [ { label: "▶ Activate", next: "active" }, { label: "❌ Cancel", next: "cancelled" }, ], blocked: [ { label: "▶ Activate", next: "active" }, { label: "📋 Queue", next: "queued" }, ], completed: [{ label: "🔄 Requeue", next: "queued" }], cancelled: [{ label: "🔄 Requeue", next: "queued" }], }; function timeAgo(dateStr: string): string { const seconds = Math.floor((Date.now() - new Date(dateStr).getTime()) / 1000); if (seconds < 60) return "just now"; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ago`; const days = Math.floor(hours / 24); return `${days}d ago`; } interface TaskCardProps { task: Task; onStatusChange: (id: string, status: TaskStatus) => void; onMoveUp?: () => void; onMoveDown?: () => void; isFirst?: boolean; isLast?: boolean; isActive?: boolean; onClick?: () => void; projectName?: string; } export function TaskCard({ task, onStatusChange, onMoveUp, onMoveDown, isFirst, isLast, isActive, onClick, projectName, }: TaskCardProps) { const actions = statusActions[task.status] || []; const noteCount = task.progressNotes?.length || 0; const displayId = task.taskNumber ? `HQ-${task.taskNumber}` : task.id.slice(0, 8); return (
{/* Top row: title + expand chevron */}
{isActive && ( )}

{task.title}

{ e.stopPropagation(); navigator.clipboard.writeText(displayId); }} > {displayId} {task.priority} {task.source} {/* Project badge */} {projectName && ( 📁 {projectName} )} {/* Assignee badge */} {task.assigneeName && ( 👤 {task.assigneeName} )} {timeAgo(task.createdAt)} {noteCount > 0 && ( 💬 {noteCount} )}
{task.description && (

{task.description}

)} {/* Due date and subtask badges */}
{task.dueDate && (() => { const due = new Date(task.dueDate); const diffMs = due.getTime() - Date.now(); const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24)); const isOverdue = diffMs < 0; const isDueSoon = diffDays <= 2 && !isOverdue; return ( 📅 {isOverdue ? `${Math.abs(diffDays)}d overdue` : diffDays === 0 ? "today" : diffDays === 1 ? "tomorrow" : `${diffDays}d`} ); })()} {task.subtasks?.length > 0 && (() => { const done = task.subtasks.filter(s => s.completed).length; const total = task.subtasks.length; const pct = Math.round((done / total) * 100); return ( {done}/{total} ); })()}
{/* Expand chevron - always visible */}
{/* Action buttons row - hidden on mobile, shown on sm+ */}
e.stopPropagation()}> {/* Reorder buttons for queued tasks */} {task.status === "queued" && (
)} {/* Quick status actions */} {actions.slice(0, 2).map((action) => ( ))}
); }