import { useTranslation } from 'react-i18next'; 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 { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger, } from "@/components/ui/context-menu"; import { Clock, Calendar, Play, Pause, MoreHorizontal, Edit, Trash2, Timer, CheckCircle, X } from "lucide-react"; import { Task, Label } from '@shared/schema'; import { useQuery } from '@tanstack/react-query'; import { Checkbox } from "@/components/ui/checkbox"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/ui/tooltip"; 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) { const { t } = useTranslation(); // 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`; }; const handleToggleComplete = (e: React.MouseEvent) => { e.stopPropagation(); if (task.status === 'done') { onStatusChange?.('todo'); } else { onStatusChange?.('done'); } }; return (
{/* Checkbox for quick completion */}

{t('taskCard.toggleComplete')}

{ onEdit?.(); console.log(`Task card clicked: ${task.title}`); }} >

{task.title}

{task.description && (

{task.description}

)}
{t(`priority.${task.priority}`)} {t(`status.${task.status}`)} {task.dueDate && (
{task.dueDate.toLocaleDateString()}
)}
{(task.timeTracked > 0 || task.isTracking) && (
{task.timeTracked > 0 ? formatTime(task.timeTracked) : '0m'} {task.isTracking && ` (${t('taskCard.running')})`}
)}
{/* Quick delete button */} {onDelete && (

{t('taskCard.quickDelete')}

)} e.stopPropagation()}> { e.stopPropagation(); onEdit?.(); console.log(`Edit task: ${task.title}`); }} data-testid={`menu-edit-${task.id}`} > {t('taskCard.editTask')} { e.stopPropagation(); handleToggleTimer(); }} data-testid={`menu-timer-${task.id}`} > {task.isTracking ? t('taskCard.stopTimer') : t('taskCard.startTimer')} {task.status !== 'done' && ( { e.stopPropagation(); onStatusChange?.('done'); console.log(`Mark task as done: ${task.title}`); }} data-testid={`menu-complete-${task.id}`} > {t('taskCard.markAsDone')} )} {task.status === 'todo' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); console.log(`Start working on: ${task.title}`); }} data-testid={`menu-start-${task.id}`} > {t('taskCard.startWorking')} )} {task.status === 'inProgress' && ( { e.stopPropagation(); onStatusChange?.('todo'); console.log(`Move back to todo: ${task.title}`); }} data-testid={`menu-todo-${task.id}`} > {t('taskCard.moveToTodo')} )} {task.status === 'done' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); console.log(`Reopen task: ${task.title}`); }} data-testid={`menu-reopen-${task.id}`} > {t('taskCard.reopenTask')} )} {onDelete && ( { e.stopPropagation(); onDelete(); console.log(`Delete task: ${task.title}`); }} className="text-destructive" data-testid={`menu-delete-${task.id}`} > {t('taskCard.deleteTask')} )}
{ e.stopPropagation(); onEdit?.(); }} data-testid={`context-menu-edit-${task.id}`} > {t('taskCard.editTask')} { e.stopPropagation(); handleToggleTimer(); }} data-testid={`context-menu-timer-${task.id}`} > {task.isTracking ? t('taskCard.stopTimer') : t('taskCard.startTimer')} {task.status !== 'done' && ( { e.stopPropagation(); onStatusChange?.('done'); }} data-testid={`context-menu-complete-${task.id}`} > {t('taskCard.markAsDone')} )} {task.status === 'todo' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); }} data-testid={`context-menu-start-${task.id}`} > {t('taskCard.startWorking')} )} {task.status === 'inProgress' && ( { e.stopPropagation(); onStatusChange?.('todo'); }} data-testid={`context-menu-todo-${task.id}`} > {t('taskCard.moveToTodo')} )} {task.status === 'done' && ( { e.stopPropagation(); onStatusChange?.('inProgress'); }} data-testid={`context-menu-reopen-${task.id}`} > {t('taskCard.reopenTask')} )} {onDelete && ( { e.stopPropagation(); onDelete(); }} className="text-destructive" data-testid={`context-menu-delete-${task.id}`} > {t('taskCard.deleteTask')} )}
); }