From 4b96a8c939b4adc48499b9d6385d476f5b59ef22 Mon Sep 17 00:00:00 2001 From: paul-nothaft <40865108-paul-nothaft@users.noreply.replit.com> Date: Thu, 11 Sep 2025 22:18:44 +0000 Subject: [PATCH] Add ability to delete tasks and improve task card interactions Refactors the KanbanBoard and TaskCard components to include a task deletion functionality and enhance user interaction with task details through a dropdown menu. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ceced2fc-aa46-458d-ba87-ddd4b7bb1518 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/659922a9-0087-461c-90dd-6d9a58b81d4d/ceced2fc-aa46-458d-ba87-ddd4b7bb1518/P2PZNJ9 --- .replit | 4 +- client/src/components/KanbanBoard.tsx | 27 ++++- client/src/components/TaskCard.tsx | 137 +++++++++++++++++++++++--- 3 files changed, 150 insertions(+), 18 deletions(-) diff --git a/.replit b/.replit index 410a32e..3f84a4e 100644 --- a/.replit +++ b/.replit @@ -19,8 +19,8 @@ localPort = 35345 externalPort = 3002 [[ports]] -localPort = 40125 -externalPort = 3001 +localPort = 40265 +externalPort = 3003 [[ports]] localPort = 41353 diff --git a/client/src/components/KanbanBoard.tsx b/client/src/components/KanbanBoard.tsx index 33ac8f8..51efc18 100644 --- a/client/src/components/KanbanBoard.tsx +++ b/client/src/components/KanbanBoard.tsx @@ -14,11 +14,12 @@ interface KanbanBoardProps { onTaskStatusChange?: (taskId: string, newStatus: Task['status']) => void; onTaskUpdate?: (taskId: string, updates: Partial) => void; onTaskClick?: (task: Task) => void; + onTaskDelete?: (taskId: string) => void; } type ViewMode = 'traditional' | 'weekly' | 'monthly'; -export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, onTaskClick }: KanbanBoardProps) { +export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, onTaskClick, onTaskDelete }: KanbanBoardProps) { const [viewMode, setViewMode] = useState('traditional'); const [currentDate, setCurrentDate] = useState(new Date()); const [draggedTask, setDraggedTask] = useState(null); @@ -199,6 +200,14 @@ export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, o onTaskClick?.(task); console.log(`Task clicked from board: ${task.title}`); }} + onDelete={() => { + onTaskDelete?.(task.id); + console.log(`Delete task from board: ${task.title}`); + }} + onStatusChange={(newStatus) => { + onTaskStatusChange?.(task.id, newStatus); + console.log(`Task ${task.title} status changed to ${newStatus}`); + }} isDragging={draggedTask === task.id} /> @@ -261,6 +270,14 @@ export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, o onTaskClick?.(task); console.log(`Task clicked from board: ${task.title}`); }} + onDelete={() => { + onTaskDelete?.(task.id); + console.log(`Delete task from board: ${task.title}`); + }} + onStatusChange={(newStatus) => { + onTaskStatusChange?.(task.id, newStatus); + console.log(`Task ${task.title} status changed to ${newStatus}`); + }} isDragging={draggedTask === task.id} /> @@ -323,6 +340,14 @@ export default function KanbanBoard({ tasks, onTaskStatusChange, onTaskUpdate, o onTaskClick?.(task); console.log(`Task clicked from board: ${task.title}`); }} + onDelete={() => { + onTaskDelete?.(task.id); + console.log(`Delete task from board: ${task.title}`); + }} + onStatusChange={(newStatus) => { + onTaskStatusChange?.(task.id, newStatus); + console.log(`Task ${task.title} status changed to ${newStatus}`); + }} isDragging={draggedTask === task.id} /> diff --git a/client/src/components/TaskCard.tsx b/client/src/components/TaskCard.tsx index 834cb9b..8f7e7d6 100644 --- a/client/src/components/TaskCard.tsx +++ b/client/src/components/TaskCard.tsx @@ -1,7 +1,14 @@ import { Card } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; -import { Clock, Calendar, Play, Pause, MoreHorizontal } from "lucide-react"; +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 { useState } from "react"; import { Task, Label } from '@shared/schema'; import { useQuery } from '@tanstack/react-query'; @@ -11,11 +18,12 @@ interface TaskCardProps { onPlay?: () => void; onPause?: () => void; onEdit?: () => void; + onDelete?: () => void; onStatusChange?: (status: Task['status']) => void; isDragging?: boolean; } -export default function TaskCard({ task, onPlay, onPause, onEdit, onStatusChange, isDragging }: TaskCardProps) { +export default function TaskCard({ task, onPlay, onPause, onEdit, onDelete, onStatusChange, isDragging }: TaskCardProps) { const [isTimerRunning, setIsTimerRunning] = useState(task.isTracking); // Fetch labels to get the label color @@ -122,19 +130,118 @@ export default function TaskCard({ task, onPlay, onPause, onEdit, onStatusChange
- + + + + + 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}`} + > + + {isTimerRunning ? '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 + + )} + +