import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Clock, Calendar, Play, Pause, MoreHorizontal, Edit, Trash2, Timer, CheckCircle } from "lucide-react"; import { Task, Label } from '@shared/schema'; import { useQuery } from '@tanstack/react-query'; interface TaskCardProps { task: Task; onStartTimer?: () => void; onStopTimer?: () => void; onEdit?: () => void; onDelete?: () => void; onStatusChange?: (status: Task['status']) => void; isDragging?: boolean; } export default function TaskCard({ task, onStartTimer, onStopTimer, onEdit, onDelete, onStatusChange, isDragging }: TaskCardProps) { // Fetch labels to get the label color const { data: labels = [] } = useQuery({ queryKey: ['/api/labels'], staleTime: 5 * 60 * 1000, // 5 minutes cache refetchOnWindowFocus: false, }); // Find the label for this task const taskLabel = task.labelId && labels.length > 0 ? labels.find(label => label.id === task.labelId) : null; const handleToggleTimer = () => { if (task.isTracking) { onStopTimer?.(); console.log(`Timer stopped for task: ${task.title}`); } else { onStartTimer?.(); console.log(`Timer started for task: ${task.title}`); } }; const getPriorityColor = (priority: string) => { switch (priority) { case 'high': return 'bg-destructive text-destructive-foreground'; case 'medium': return 'bg-yellow-500 text-white'; default: return 'bg-muted text-muted-foreground'; } }; const getStatusColor = (status: string) => { switch (status) { case 'done': return 'bg-green-500 text-white'; case 'inProgress': return 'bg-primary text-primary-foreground'; default: return 'bg-muted text-muted-foreground'; } }; const formatTime = (minutes: number) => { if (minutes < 60) { return `${minutes}m`; } const hours = Math.floor(minutes / 60); const mins = minutes % 60; if (mins === 0) { return `${hours}h`; } return `${hours}h ${mins}m`; }; return ( { onEdit?.(); console.log(`Task card clicked: ${task.title}`); }} >

{task.title}

{task.description && (

{task.description}

)}
{task.priority} {task.status.replace(/([A-Z])/g, ' $1').toLowerCase()} {task.dueDate && (
{task.dueDate.toLocaleDateString()}
)}
{(task.timeTracked > 0 || task.isTracking) && (
{task.timeTracked > 0 ? formatTime(task.timeTracked) : '0m'} {task.isTracking && ' (running)'}
)}
e.stopPropagation()}> { e.stopPropagation(); onEdit?.(); console.log(`Edit task: ${task.title}`); }} data-testid={`menu-edit-${task.id}`} > Edit Task { e.stopPropagation(); handleToggleTimer(); }} data-testid={`menu-timer-${task.id}`} > {task.isTracking ? 'Stop Timer' : 'Start Timer'} {task.status !== 'done' && ( { e.stopPropagation(); onStatusChange?.('done'); console.log(`Mark task as done: ${task.title}`); }} data-testid={`menu-complete-${task.id}`} > Mark as Done )} {task.status === 'todo' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); console.log(`Start working on: ${task.title}`); }} data-testid={`menu-start-${task.id}`} > Start Working )} {task.status === 'inProgress' && ( { e.stopPropagation(); onStatusChange?.('todo'); console.log(`Move back to todo: ${task.title}`); }} data-testid={`menu-todo-${task.id}`} > Move to Todo )} {task.status === 'done' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); console.log(`Reopen task: ${task.title}`); }} data-testid={`menu-reopen-${task.id}`} > Reopen Task )} {onDelete && ( { e.stopPropagation(); onDelete(); console.log(`Delete task: ${task.title}`); }} className="text-destructive" data-testid={`menu-delete-${task.id}`} > Delete Task )}
); }