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
This commit is contained in:
@@ -19,8 +19,8 @@ localPort = 35345
|
||||
externalPort = 3002
|
||||
|
||||
[[ports]]
|
||||
localPort = 40125
|
||||
externalPort = 3001
|
||||
localPort = 40265
|
||||
externalPort = 3003
|
||||
|
||||
[[ports]]
|
||||
localPort = 41353
|
||||
|
||||
@@ -14,11 +14,12 @@ interface KanbanBoardProps {
|
||||
onTaskStatusChange?: (taskId: string, newStatus: Task['status']) => void;
|
||||
onTaskUpdate?: (taskId: string, updates: Partial<Task>) => 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<ViewMode>('traditional');
|
||||
const [currentDate, setCurrentDate] = useState(new Date());
|
||||
const [draggedTask, setDraggedTask] = useState<string | null>(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}
|
||||
/>
|
||||
</div>
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -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
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onEdit?.();
|
||||
console.log(`Edit task: ${task.title}`);
|
||||
}}
|
||||
data-testid={`button-edit-${task.id}`}
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<MoreHorizontal className="w-3 h-3" />
|
||||
</Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="ghost"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
data-testid={`button-menu-${task.id}`}
|
||||
className="w-6 h-6"
|
||||
>
|
||||
<MoreHorizontal className="w-3 h-3" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" onClick={(e) => e.stopPropagation()}>
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onEdit?.();
|
||||
console.log(`Edit task: ${task.title}`);
|
||||
}}
|
||||
data-testid={`menu-edit-${task.id}`}
|
||||
>
|
||||
<Edit className="w-4 h-4 mr-2" />
|
||||
Edit Task
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleToggleTimer();
|
||||
}}
|
||||
data-testid={`menu-timer-${task.id}`}
|
||||
>
|
||||
<Timer className="w-4 h-4 mr-2" />
|
||||
{isTimerRunning ? 'Stop Timer' : 'Start Timer'}
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
{task.status !== 'done' && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onStatusChange?.('done');
|
||||
console.log(`Mark task as done: ${task.title}`);
|
||||
}}
|
||||
data-testid={`menu-complete-${task.id}`}
|
||||
>
|
||||
<CheckCircle className="w-4 h-4 mr-2" />
|
||||
Mark as Done
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{task.status === 'todo' && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onStatusChange?.('inProgress');
|
||||
console.log(`Start working on: ${task.title}`);
|
||||
}}
|
||||
data-testid={`menu-start-${task.id}`}
|
||||
>
|
||||
<Play className="w-4 h-4 mr-2" />
|
||||
Start Working
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{task.status === 'inProgress' && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onStatusChange?.('todo');
|
||||
console.log(`Move back to todo: ${task.title}`);
|
||||
}}
|
||||
data-testid={`menu-todo-${task.id}`}
|
||||
>
|
||||
<Clock className="w-4 h-4 mr-2" />
|
||||
Move to Todo
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
{task.status === 'done' && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onStatusChange?.('inProgress');
|
||||
console.log(`Reopen task: ${task.title}`);
|
||||
}}
|
||||
data-testid={`menu-reopen-${task.id}`}
|
||||
>
|
||||
<Play className="w-4 h-4 mr-2" />
|
||||
Reopen Task
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
{onDelete && (
|
||||
<DropdownMenuItem
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onDelete();
|
||||
console.log(`Delete task: ${task.title}`);
|
||||
}}
|
||||
className="text-destructive"
|
||||
data-testid={`menu-delete-${task.id}`}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 mr-2" />
|
||||
Delete Task
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<Button
|
||||
size="icon"
|
||||
|
||||
Reference in New Issue
Block a user