The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\stores\taskStore.ts has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    34→  status?: string
    35→  agent_type?: string
    36→}
    37→
    38→interface TaskStore {
    39→  tasks: Task[]
    40→  isLoading: boolean
    41→  error: string | null
    42→  deletingTaskIds: Set<number>
    43→  fetchTasks: (projectId: number) => Promise<void>
    44→  createTask: (projectId: number, task: TaskCreate) => Promise<Task>
    45→  updateTask: (taskId: number, updates: TaskUpdate) => Promise<Task>
    46→  updateTaskStatus: (taskId: number, status: string) => Promise<void>
    47→  deleteTask: (taskId: number) => Promise<void>
    48→  isTaskDeleting: (taskId: number) => boolean
    49→  clearTasks: () => void
    50→}
    51→
    52→const API_BASE = 'http://localhost:8000/api'
    53→
    54→export const useTaskStore = create<TaskStore>((set, get) => ({

interface TaskStore {
  tasks: Task[]
  isLoading: boolean
  error: string | null
  deletingTaskIds: Set<number>
  fetchTasks: (projectId: number) => Promise<void>
  createTask: (projectId: number, task: TaskCreate) => Promise<Task>
  updateTask: (taskId: number, updates: TaskUpdate) => Promise<Task>
  updateTaskStatus: (taskId: number, status: string) => Promise<void>
  deleteTask: (taskId: number) => Promise<void>
  isTaskDeleting: (taskId: number) => boolean
  clearTasks: () => void
}

import { create } from 'zustand'
import { useToastStore } from '../components/Toast'

export interface Task {
  id: number
  project_id: number
  spec_id: number | null
  phase_id: number | null
  name: string
  description: string | null
  status: string
  priority: number
  estimated_time: number | null
  actual_time: number | null
  agent_type: string | null
  iteration_count: number
  flagged_for_review: boolean
  depends_on: number[] | null
  created_at: string
  updated_at: string
}

export interface TaskCreate {
  name: string
  description?: string
  priority?: number
  agent_type?: string
}

export interface TaskUpdate {
  name?: string
  description?: string
  priority?: number
  status?: string
  agent_type?: string
}

interface TaskStore {
  tasks: Task[]
  isLoading: boolean
  error: string | null
  fetchTasks: (projectId: number) => Promise<void>
  createTask: (projectId: number, task: TaskCreate) => Promise<Task>
  updateTask: (taskId: number, updates: TaskUpdate) => Promise<Task>
  updateTaskStatus: (taskId: number, status: string) => Promise<void>
  deleteTask: (taskId: number) => Promise<void>
  clearTasks: () => void
}

const API_BASE = 'http://localhost:8000/api'

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,

  fetchTasks: async (projectId: number) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`)
      if (!response.ok) throw new Error('Failed to fetch tasks')
      const tasks = await response.json()
      set({ tasks, isLoading: false })
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to load tasks', errorMessage)
    }
  },

  createTask: async (projectId: number, task: TaskCreate) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(task),
      })
      if (!response.ok) throw new Error('Failed to create task')
      const newTask = await response.json()
      set((state) => ({
        tasks: [...state.tasks, newTask],
        isLoading: false,
      }))
      return newTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to create task', errorMessage)
      throw error
    }
  },

  updateTask: async (taskId: number, updates: TaskUpdate) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      })
      if (!response.ok) throw new Error('Failed to update task')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
      return updatedTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task', errorMessage)
      throw error
    }
  },

  updateTaskStatus: async (taskId: number, status: string) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}/status`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ status }),
      })
      if (!response.ok) throw new Error('Failed to update task status')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task status', errorMessage)
      throw error
    }
  },

  deleteTask: async (taskId: number) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    }
  },

  clearTasks: () => {
    set({ tasks: [], error: null })
  },
}))

+  isTaskDeleting: (taskId: number) => boolean


Edit

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,
  deletingTaskIds: new Set<number>(),


The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\stores\taskStore.ts has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    50→}
    51→
    52→const API_BASE = 'http://localhost:8000/api'
    53→
    54→export const useTaskStore = create<TaskStore>((set, get) => ({
    55→  tasks: [],
    56→  isLoading: false,
    57→  error: null,
    58→  deletingTaskIds: new Set<number>(),
    59→
    60→  fetchTasks: async (projectId: number) => {
    61→    set({ isLoading: true, error: null })
    62→    try {

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,
  deletingTaskIds: new Set<number>(),

import { create } from 'zustand'
import { useToastStore } from '../components/Toast'

export interface Task {
  id: number
  project_id: number
  spec_id: number | null
  phase_id: number | null
  name: string
  description: string | null
  status: string
  priority: number
  estimated_time: number | null
  actual_time: number | null
  agent_type: string | null
  iteration_count: number
  flagged_for_review: boolean
  depends_on: number[] | null
  created_at: string
  updated_at: string
}

export interface TaskCreate {
  name: string
  description?: string
  priority?: number
  agent_type?: string
}

export interface TaskUpdate {
  name?: string
  description?: string
  priority?: number
  status?: string
  agent_type?: string
}

interface TaskStore {
  tasks: Task[]
  isLoading: boolean
  error: string | null
  deletingTaskIds: Set<number>
  fetchTasks: (projectId: number) => Promise<void>
  createTask: (projectId: number, task: TaskCreate) => Promise<Task>
  updateTask: (taskId: number, updates: TaskUpdate) => Promise<Task>
  updateTaskStatus: (taskId: number, status: string) => Promise<void>
  deleteTask: (taskId: number) => Promise<void>
  isTaskDeleting: (taskId: number) => boolean
  clearTasks: () => void
}

const API_BASE = 'http://localhost:8000/api'

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,

  fetchTasks: async (projectId: number) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`)
      if (!response.ok) throw new Error('Failed to fetch tasks')
      const tasks = await response.json()
      set({ tasks, isLoading: false })
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to load tasks', errorMessage)
    }
  },

  createTask: async (projectId: number, task: TaskCreate) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(task),
      })
      if (!response.ok) throw new Error('Failed to create task')
      const newTask = await response.json()
      set((state) => ({
        tasks: [...state.tasks, newTask],
        isLoading: false,
      }))
      return newTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to create task', errorMessage)
      throw error
    }
  },

  updateTask: async (taskId: number, updates: TaskUpdate) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      })
      if (!response.ok) throw new Error('Failed to update task')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
      return updatedTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task', errorMessage)
      throw error
    }
  },

  updateTaskStatus: async (taskId: number, status: string) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}/status`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ status }),
      })
      if (!response.ok) throw new Error('Failed to update task status')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task status', errorMessage)
      throw error
    }
  },

  deleteTask: async (taskId: number) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    }
  },

  clearTasks: () => {
    set({ tasks: [], error: null })
  },
}))


Now let me update the deleteTask function to use the deletingTaskIds set:


  deleteTask: async (taskId: number) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    }
  },

  deleteTask: async (taskId: number) => {
    // Prevent duplicate delete operations
    const { deletingTaskIds } = get()
    if (deletingTaskIds.has(taskId)) {
      // Already deleting this task, silently return
      return
    }

    // Mark task as being deleted
    set((state) => ({
      deletingTaskIds: new Set([...state.deletingTaskIds, taskId])
    }))

    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    } finally {
      // Remove task from deleting set
      set((state) => {
        const newSet = new Set(state.deletingTaskIds)
        newSet.delete(taskId)
        return { deletingTaskIds: newSet }
      })
    }
  },

  isTaskDeleting: (taskId: number) => {
    return get().deletingTaskIds.has(taskId)
  },


The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\stores\taskStore.ts has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   138→      throw error
   139→    }
   140→  },
   141→
   142→  deleteTask: async (taskId: number) => {
   143→    // Prevent duplicate delete operations
   144→    const { deletingTaskIds } = get()
   145→    if (deletingTaskIds.has(taskId)) {
   146→      // Already deleting this task, silently return
   147→      return
   148→    }
   149→
   150→    // Mark task as being deleted
   151→    set((state) => ({
   152→      deletingTaskIds: new Set([...state.deletingTaskIds, taskId])
   153→    }))
   154→
   155→    try {
   156→      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
   157→        method: 'DELETE',
   158→      })
   159→      if (!response.ok) throw new Error('Failed to delete task')
   160→      set((state) => ({
   161→        tasks: state.tasks.filter((t) => t.id !== taskId),
   162→      }))
   163→    } catch (error) {
   164→      const errorMessage = (error as Error).message
   165→      set({ error: errorMessage })
   166→      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
   167→      throw error
   168→    } finally {
   169→      // Remove task from deleting set
   170→      set((state) => {
   171→        const newSet = new Set(state.deletingTaskIds)
   172→        newSet.delete(taskId)
   173→        return { deletingTaskIds: newSet }
   174→      })
   175→    }
   176→  },
   177→
   178→  isTaskDeleting: (taskId: number) => {
   179→    return get().deletingTaskIds.has(taskId)
   180→  },
   181→
   182→  clearTasks: () => {
   183→    set({ tasks: [], error: null })
   184→  },

  deleteTask: async (taskId: number) => {
    // Prevent duplicate delete operations
    const { deletingTaskIds } = get()
    if (deletingTaskIds.has(taskId)) {
      // Already deleting this task, silently return
      return
    }

    // Mark task as being deleted
    set((state) => ({
      deletingTaskIds: new Set([...state.deletingTaskIds, taskId])
    }))

    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    } finally {
      // Remove task from deleting set
      set((state) => {
        const newSet = new Set(state.deletingTaskIds)
        newSet.delete(taskId)
        return { deletingTaskIds: newSet }
      })
    }
  },

  isTaskDeleting: (taskId: number) => {
    return get().deletingTaskIds.has(taskId)
  },

import { create } from 'zustand'
import { useToastStore } from '../components/Toast'

export interface Task {
  id: number
  project_id: number
  spec_id: number | null
  phase_id: number | null
  name: string
  description: string | null
  status: string
  priority: number
  estimated_time: number | null
  actual_time: number | null
  agent_type: string | null
  iteration_count: number
  flagged_for_review: boolean
  depends_on: number[] | null
  created_at: string
  updated_at: string
}

export interface TaskCreate {
  name: string
  description?: string
  priority?: number
  agent_type?: string
}

export interface TaskUpdate {
  name?: string
  description?: string
  priority?: number
  status?: string
  agent_type?: string
}

interface TaskStore {
  tasks: Task[]
  isLoading: boolean
  error: string | null
  deletingTaskIds: Set<number>
  fetchTasks: (projectId: number) => Promise<void>
  createTask: (projectId: number, task: TaskCreate) => Promise<Task>
  updateTask: (taskId: number, updates: TaskUpdate) => Promise<Task>
  updateTaskStatus: (taskId: number, status: string) => Promise<void>
  deleteTask: (taskId: number) => Promise<void>
  isTaskDeleting: (taskId: number) => boolean
  clearTasks: () => void
}

const API_BASE = 'http://localhost:8000/api'

export const useTaskStore = create<TaskStore>((set, get) => ({
  tasks: [],
  isLoading: false,
  error: null,
  deletingTaskIds: new Set<number>(),

  fetchTasks: async (projectId: number) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`)
      if (!response.ok) throw new Error('Failed to fetch tasks')
      const tasks = await response.json()
      set({ tasks, isLoading: false })
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to load tasks', errorMessage)
    }
  },

  createTask: async (projectId: number, task: TaskCreate) => {
    set({ isLoading: true, error: null })
    try {
      const response = await fetch(`${API_BASE}/projects/${projectId}/tasks`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(task),
      })
      if (!response.ok) throw new Error('Failed to create task')
      const newTask = await response.json()
      set((state) => ({
        tasks: [...state.tasks, newTask],
        isLoading: false,
      }))
      return newTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage, isLoading: false })
      useToastStore.getState().addToast('error', 'Failed to create task', errorMessage)
      throw error
    }
  },

  updateTask: async (taskId: number, updates: TaskUpdate) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(updates),
      })
      if (!response.ok) throw new Error('Failed to update task')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
      return updatedTask
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task', errorMessage)
      throw error
    }
  },

  updateTaskStatus: async (taskId: number, status: string) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}/status`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ status }),
      })
      if (!response.ok) throw new Error('Failed to update task status')
      const updatedTask = await response.json()
      set((state) => ({
        tasks: state.tasks.map((t) =>
          t.id === taskId ? updatedTask : t
        ),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to update task status', errorMessage)
      throw error
    }
  },

  deleteTask: async (taskId: number) => {
    try {
      const response = await fetch(`${API_BASE}/tasks/${taskId}`, {
        method: 'DELETE',
      })
      if (!response.ok) throw new Error('Failed to delete task')
      set((state) => ({
        tasks: state.tasks.filter((t) => t.id !== taskId),
      }))
    } catch (error) {
      const errorMessage = (error as Error).message
      set({ error: errorMessage })
      useToastStore.getState().addToast('error', 'Failed to delete task', errorMessage)
      throw error
    }
  },

  clearTasks: () => {
    set({ tasks: [], error: null })
  },
}))

+    // Prevent duplicate delete operations

+      // Already deleting this task, silently return

+      deletingTaskIds: new Set([...state.deletingTaskIds, taskId])

+        const newSet = new Set(state.deletingTaskIds)

+        return { deletingTaskIds: newSet }

+  isTaskDeleting: (taskId: number) => {

+    return get().deletingTaskIds.has(taskId)


Now let me update the KanbanBoard to use the `isTaskDeleting` function and close the dialog immediately:


const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isLoading } = useTaskStore()

const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isTaskDeleting, isLoading } = useTaskStore()


The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\pages\KanbanBoard.tsx has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
    33→
    34→export default function KanbanBoard() {
    35→  const [searchParams, setSearchParams] = useSearchParams()
    36→  const { currentProject } = useProjectStore()
    37→  const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isTaskDeleting, isLoading } = useTaskStore()
    38→  const [showAddDialog, setShowAddDialog] = useState(false)
    39→  const [newTaskName, setNewTaskName] = useState('')
    40→  const [newTaskDescription, setNewTaskDescription] = useState('')
    41→  const [newTaskPriority, setNewTaskPriority] = useState(0)

import { useEffect, useState, useMemo } from 'react'
import { useSearchParams } from 'react-router-dom'
import { Plus, X, GripVertical, Clock, User, RefreshCw, Flag, Pencil, Check, Trash2, Filter, ArrowUpDown, LayoutGrid, List, ChevronLeft, ChevronRight } from 'lucide-react'
import * as Dialog from '@radix-ui/react-dialog'
import * as AlertDialog from '@radix-ui/react-alert-dialog'
import { useProjectStore } from '../stores/projectStore'
import { useTaskStore, Task, TaskCreate, TaskUpdate } from '../stores/taskStore'

const ITEMS_PER_PAGE = 10

const COLUMNS = [
  { id: 'backlog', title: 'Backlog', color: 'border-slate-500' },
  { id: 'in_progress', title: 'In Progress', color: 'border-accent' },
  { id: 'qa', title: 'QA', color: 'border-primary-400' },
  { id: 'done', title: 'Done', color: 'border-green-400' },
  { id: 'blocked', title: 'Blocked', color: 'border-destructive' },
]

const PRIORITY_LABELS: Record<number, string> = {
  0: 'Low',
  1: 'Medium',
  2: 'High',
  3: 'Critical',
}

const STATUS_LABELS: Record<string, string> = {
  backlog: 'Backlog',
  in_progress: 'In Progress',
  qa: 'QA',
  done: 'Done',
  blocked: 'Blocked',
}

export default function KanbanBoard() {
  const [searchParams, setSearchParams] = useSearchParams()
  const { currentProject } = useProjectStore()
  const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isLoading } = useTaskStore()
  const [showAddDialog, setShowAddDialog] = useState(false)
  const [newTaskName, setNewTaskName] = useState('')
  const [newTaskDescription, setNewTaskDescription] = useState('')
  const [newTaskPriority, setNewTaskPriority] = useState(0)
  const [isCreating, setIsCreating] = useState(false)
  const [draggedTask, setDraggedTask] = useState<number | null>(null)
  const [selectedTask, setSelectedTask] = useState<Task | null>(null)
  const [isEditing, setIsEditing] = useState(false)
  const [editName, setEditName] = useState('')
  const [editDescription, setEditDescription] = useState('')
  const [editPriority, setEditPriority] = useState(0)
  const [isSaving, setIsSaving] = useState(false)
  const [showDeleteDialog, setShowDeleteDialog] = useState(false)
  const [isDeleting, setIsDeleting] = useState(false)
  const [showUnsavedDialog, setShowUnsavedDialog] = useState(false)
  const [pendingCloseAction, setPendingCloseAction] = useState<'close' | 'cancel' | null>(null)
  // Filter and Sort state - initialize from URL params
  const getInitialPriorityFilter = (): number | 'all' => {
    const param = searchParams.get('priority')
    if (param === 'all' || param === null) return 'all'
    const num = parseInt(param, 10)
    return [0, 1, 2, 3].includes(num) ? num : 'all'
  }
  const getInitialSortOrder = (): 'newest' | 'oldest' | 'priority' => {
    const param = searchParams.get('sort')
    if (param === 'newest' || param === 'oldest' || param === 'priority') return param
    return 'newest'
  }
  const getInitialViewMode = (): 'kanban' | 'list' => {
    const param = searchParams.get('view')
    if (param === 'list') return 'list'
    return 'kanban'
  }

  const [priorityFilter, setPriorityFilter] = useState<number | 'all'>(getInitialPriorityFilter)
  const [sortOrder, setSortOrder] = useState<'newest' | 'oldest' | 'priority'>(getInitialSortOrder)
  // View mode and pagination state
  const [viewMode, setViewMode] = useState<'kanban' | 'list'>(getInitialViewMode)
  const [currentPage, setCurrentPage] = useState(1)

  useEffect(() => {
    if (currentProject?.id) {
      fetchTasks(currentProject.id)
    }
  }, [currentProject?.id, fetchTasks])

  // Handle deep linking - select task from URL param after tasks are loaded
  useEffect(() => {
    const taskIdParam = searchParams.get('task')
    if (taskIdParam && tasks.length > 0) {
      const taskId = parseInt(taskIdParam, 10)
      const task = tasks.find(t => t.id === taskId)
      if (task) {
        setSelectedTask(task)
      }
    }
  }, [searchParams, tasks])

  // Update URL when task is selected
  const handleSelectTask = (task: Task) => {
    setSelectedTask(task)
    const newParams = new URLSearchParams(searchParams)
    newParams.set('task', task.id.toString())
    setSearchParams(newParams)
  }

  // Clear task from URL when panel is closed
  const clearTaskFromUrl = () => {
    const newParams = new URLSearchParams(searchParams)
    newParams.delete('task')
    setSearchParams(newParams)
  }

  // Update URL when filter changes
  const handlePriorityFilterChange = (value: number | 'all') => {
    setPriorityFilter(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'all') {
      newParams.delete('priority')
    } else {
      newParams.set('priority', value.toString())
    }
    setSearchParams(newParams)
  }

  // Update URL when sort changes
  const handleSortOrderChange = (value: 'newest' | 'oldest' | 'priority') => {
    setSortOrder(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'newest') {
      newParams.delete('sort') // default value, no need to store
    } else {
      newParams.set('sort', value)
    }
    setSearchParams(newParams)
  }

  // Update URL when view mode changes
  const handleViewModeChange = (value: 'kanban' | 'list') => {
    setViewMode(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'kanban') {
      newParams.delete('view') // default value, no need to store
    } else {
      newParams.set('view', value)
    }
    setSearchParams(newParams)
  }

  // Filtered and sorted tasks
  const filteredAndSortedTasks = useMemo(() => {
    let result = [...tasks]

    // Apply priority filter
    if (priorityFilter !== 'all') {
      result = result.filter(task => task.priority === priorityFilter)
    }

    // Apply sort
    result.sort((a, b) => {
      if (sortOrder === 'newest') {
        return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
      } else if (sortOrder === 'oldest') {
        return new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
      } else {
        // priority - highest first
        return b.priority - a.priority
      }
    })

    return result
  }, [tasks, priorityFilter, sortOrder])

  // Pagination calculations
  const totalPages = Math.ceil(filteredAndSortedTasks.length / ITEMS_PER_PAGE)
  const paginatedTasks = useMemo(() => {
    const startIndex = (currentPage - 1) * ITEMS_PER_PAGE
    return filteredAndSortedTasks.slice(startIndex, startIndex + ITEMS_PER_PAGE)
  }, [filteredAndSortedTasks, currentPage])

  // Reset page when filter changes
  useEffect(() => {
    setCurrentPage(1)
  }, [priorityFilter, sortOrder])

  const getTasksByStatus = (status: string) => {
    return filteredAndSortedTasks.filter((task) => task.status === status)
  }

  const handleCreateTask = async () => {
    if (!currentProject || !newTaskName.trim()) return
    setIsCreating(true)
    try {
      const taskData: TaskCreate = {
        name: newTaskName.trim(),
        description: newTaskDescription.trim() || undefined,
        priority: newTaskPriority,
      }
      await createTask(currentProject.id, taskData)
      setNewTaskName('')
      setNewTaskDescription('')
      setNewTaskPriority(0)
      setShowAddDialog(false)
    } catch (error) {
      console.error('Failed to create task:', error)
    } finally {
      setIsCreating(false)
    }
  }

  const handleDragStart = (taskId: number) => {
    setDraggedTask(taskId)
  }

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
  }

  const handleDrop = async (targetStatus: string) => {
    if (draggedTask === null) return
    try {
      await updateTaskStatus(draggedTask, targetStatus)
    } catch (error) {
      console.error('Failed to update task status:', error)
    }
    setDraggedTask(null)
  }

  const handleStartEdit = () => {
    if (!selectedTask) return
    setEditName(selectedTask.name)
    setEditDescription(selectedTask.description || '')
    setEditPriority(selectedTask.priority)
    setIsEditing(true)
  }

  // Check if edit form has unsaved changes
  const hasUnsavedChanges = () => {
    if (!selectedTask || !isEditing) return false
    return (
      editName.trim() !== selectedTask.name ||
      (editDescription.trim() || '') !== (selectedTask.description || '') ||
      editPriority !== selectedTask.priority
    )
  }

  const handleCancelEdit = () => {
    if (hasUnsavedChanges()) {
      setPendingCloseAction('cancel')
      setShowUnsavedDialog(true)
    } else {
      setIsEditing(false)
    }
  }

  const handleClosePanel = () => {
    if (hasUnsavedChanges()) {
      setPendingCloseAction('close')
      setShowUnsavedDialog(true)
    } else {
      setSelectedTask(null)
      setIsEditing(false)
      clearTaskFromUrl()
    }
  }

  const handleDiscardChanges = () => {
    setShowUnsavedDialog(false)
    if (pendingCloseAction === 'close') {
      setSelectedTask(null)
      clearTaskFromUrl()
    }
    setIsEditing(false)
    setPendingCloseAction(null)
  }

  const handleKeepEditing = () => {
    setShowUnsavedDialog(false)
    setPendingCloseAction(null)
  }

  const handleSaveEdit = async () => {
    if (!selectedTask) return
    setIsSaving(true)
    try {
      const updates: TaskUpdate = {
        name: editName.trim(),
        description: editDescription.trim() || undefined,
        priority: editPriority,
      }
      const updatedTask = await updateTask(selectedTask.id, updates)
      setSelectedTask(updatedTask)
      setIsEditing(false)
    } catch (error) {
      console.error('Failed to update task:', error)
    } finally {
      setIsSaving(false)
    }
  }

  const handleDeleteTask = async () => {
    if (!selectedTask) return
    setIsDeleting(true)
    try {
      await deleteTask(selectedTask.id)
      setSelectedTask(null)
      setShowDeleteDialog(false)
    } catch (error) {
      console.error('Failed to delete task:', error)
    } finally {
      setIsDeleting(false)
    }
  }

  if (!currentProject) {
    return (

Select a project to view its Kanban board

    )
  }

  return (

      {/* Header */}

Kanban Board

          {/* Priority Filter */}

            <Filter size={16} className="text-slate-400" />
            <select
              value={priorityFilter === 'all' ? 'all' : priorityFilter.toString()}
              onChange={(e) => handlePriorityFilterChange(e.target.value === 'all' ? 'all' : Number(e.target.value))}
              className="px-3 py-1.5 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-accent"
            >
              <option value="all">All Priorities</option>
              <option value="3">Critical</option>
              <option value="2">High</option>
              <option value="1">Medium</option>
              <option value="0">Low</option>
            </select>

          {/* Sort Order */}

            <ArrowUpDown size={16} className="text-slate-400" />
            <select
              value={sortOrder}
              onChange={(e) => handleSortOrderChange(e.target.value as 'newest' | 'oldest' | 'priority')}
              className="px-3 py-1.5 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-accent"
            >
              <option value="newest">Newest First</option>
              <option value="oldest">Oldest First</option>
              <option value="priority">By Priority</option>
            </select>

          {/* View Mode Toggle */}

            <button
              onClick={() => handleViewModeChange('kanban')}
              className={`p-1.5 rounded ${viewMode === 'kanban' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
              title="Kanban View"
            >
              <LayoutGrid size={18} />
            </button>
            <button
              onClick={() => handleViewModeChange('list')}
              className={`p-1.5 rounded ${viewMode === 'list' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
              title="List View"
            >
              <List size={18} />
            </button>

        <Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
          <Dialog.Trigger asChild>
            <button className="btn-accent flex items-center gap-2">
              <Plus size={18} />
              Add Task
            </button>
          </Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
            <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">

                <Dialog.Title className="text-xl font-semibold text-white">
                  Add New Task
                </Dialog.Title>
                <Dialog.Close asChild>
                  <button className="text-slate-400 hover:text-white">
                    <X size={20} />
                  </button>
                </Dialog.Close>

              <Dialog.Description className="text-slate-400 mb-4">
                Create a new task for this project.
              </Dialog.Description>

                    Task Name *

                  <input
                    type="text"
                    value={newTaskName}
                    onChange={(e) => setNewTaskName(e.target.value)}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                    placeholder="Enter task name"
                  />

                    Description

                  <textarea
                    value={newTaskDescription}
                    onChange={(e) => setNewTaskDescription(e.target.value)}
                    rows={3}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent resize-none"
                    placeholder="Enter task description"
                  />

                    Priority

                  <select
                    value={newTaskPriority}
                    onChange={(e) => setNewTaskPriority(Number(e.target.value))}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                  >
                    <option value={0}>Low</option>
                    <option value={1}>Medium</option>
                    <option value={2}>High</option>
                    <option value={3}>Critical</option>
                  </select>

                <Dialog.Close asChild>
                  <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
                    Cancel
                  </button>
                </Dialog.Close>
                <button
                  onClick={handleCreateTask}
                  disabled={isCreating || !newTaskName.trim()}
                  className="px-4 py-2 text-sm bg-accent hover:bg-accent/80 text-white rounded-lg transition-colors disabled:opacity-50"
                >
                  {isCreating ? 'Creating...' : 'Create Task'}
                </button>

            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>

      {/* Main Content Area */}

        {viewMode === 'list' ? (
          /* List View with Pagination */

            {/* Task List Table */}

                    Task Name
                    Status
                    Priority
                    Created

                  {isLoading && tasks.length === 0 ? (

                        Loading...

                  ) : paginatedTasks.length === 0 ? (

                        No tasks found

                  ) : (
                    paginatedTasks.map((task) => (

 handleSelectTask(task)}
                        className={`border-t border-slate-700 hover:bg-slate-700/50 cursor-pointer ${
                          selectedTask?.id === task.id ? 'bg-slate-700' : ''
                        }`}
                      >

{task.name}

                          {task.description && (

                              {task.description}

                          )}

                            {STATUS_LABELS[task.status] || task.status}

                            {PRIORITY_LABELS[task.priority] || 'Unknown'}

                          {new Date(task.created_at).toLocaleDateString()}

                    ))
                  )}

            {/* Pagination Controls */}
            {totalPages > 1 && (

                  Showing {((currentPage - 1) * ITEMS_PER_PAGE) + 1} to {Math.min(currentPage * ITEMS_PER_PAGE, filteredAndSortedTasks.length)} of {filteredAndSortedTasks.length} tasks

                  <button
                    onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
                    disabled={currentPage === 1}
                    className="p-2 rounded-lg bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    <ChevronLeft size={18} />
                  </button>

                    {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
                      <button
                        key={page}
                        onClick={() => setCurrentPage(page)}
                        className={`w-8 h-8 rounded-lg text-sm ${
                          page === currentPage
                            ? 'bg-accent text-white'
                            : 'bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700'
                        }`}
                      >
                        {page}
                      </button>
                    ))}

                  <button
                    onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
                    disabled={currentPage === totalPages}
                    className="p-2 rounded-lg bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    <ChevronRight size={18} />
                  </button>

            )}

        ) : (
        /* Kanban Columns */
        <div className={`flex-1 flex gap-4 overflow-x-auto pb-4 ${selectedTask ? 'mr-0' : ''}`}>
          {COLUMNS.map((column) => (
          <div
            key={column.id}
            className={`flex-shrink-0 w-72 bg-slate-800 rounded-lg border-t-2 ${column.color}`}
            onDragOver={handleDragOver}
            onDrop={() => handleDrop(column.id)}
          >
            {/* Column Header */}

{column.title}

                  {getTasksByStatus(column.id).length}

            {/* Column Content */}

              {isLoading && tasks.length === 0 ? (

                  Loading...

              ) : getTasksByStatus(column.id).length === 0 ? (

                  No tasks

              ) : (
                getTasksByStatus(column.id).map((task) => (

 handleDragStart(task.id)}
                    onClick={() => handleSelectTask(task)}
                    className={`kanban-card bg-slate-900 rounded-lg p-4 border border-slate-700 cursor-pointer hover:border-slate-600 ${
                      draggedTask === task.id ? 'opacity-50' : ''
                    } ${selectedTask?.id === task.id ? 'ring-2 ring-accent' : ''}`}
                  >

                      <GripVertical size={16} className="text-slate-600 mt-0.5 flex-shrink-0" />

{task.name}

                        {task.description && (

                            {task.description}

                        )}

                          <span
                            className={`badge ${
                              column.id === 'backlog'
                                ? 'badge-backlog'
                                : column.id === 'in_progress'
                                ? 'badge-in-progress'
                                : column.id === 'qa'
                                ? 'badge-qa'
                                : column.id === 'done'
                                ? 'badge-done'
                                : 'badge-blocked'
                            }`}
                          >
                            {column.title}

                            {task.priority === 3 ? 'Critical' :
                             task.priority === 2 ? 'High' :
                             task.priority === 1 ? 'Medium' : 'Low'}

                ))
              )}

          ))}

        )}

        {/* Task Details Panel */}
        {selectedTask && (

Task Details

                {!isEditing && (
                  <>
                    <button
                      onClick={handleStartEdit}
                      className="text-slate-400 hover:text-accent transition-colors"
                      title="Edit Task"
                    >
                      <Pencil size={18} />
                    </button>
                    <AlertDialog.Root open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
                      <AlertDialog.Trigger asChild>
                        <button
                          className="text-slate-400 hover:text-destructive transition-colors"
                          title="Delete Task"
                        >
                          <Trash2 size={18} />
                        </button>
                      </AlertDialog.Trigger>
                      <AlertDialog.Portal>
                        <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
                        <AlertDialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">
                          <AlertDialog.Title className="text-xl font-semibold text-white">
                            Delete Task
                          </AlertDialog.Title>
                          <AlertDialog.Description className="mt-3 text-slate-400">
                            Are you sure you want to delete {selectedTask.name}?
                            This action cannot be undone.
                          </AlertDialog.Description>

                            <AlertDialog.Cancel asChild>
                              <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
                                Cancel
                              </button>
                            </AlertDialog.Cancel>
                            <AlertDialog.Action asChild>
                              <button
                                onClick={handleDeleteTask}
                                disabled={isDeleting}
                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
                              >
                                {isDeleting ? 'Deleting...' : 'Delete Task'}
                              </button>
                            </AlertDialog.Action>

                        </AlertDialog.Content>
                      </AlertDialog.Portal>
                    </AlertDialog.Root>
                  </>
                )}
                <button
                  onClick={handleClosePanel}
                  className="text-slate-400 hover:text-white transition-colors"
                  title="Close"
                >
                  <X size={20} />
                </button>

              {isEditing ? (
                /* Edit Form */

                    Name *
                    <input
                      type="text"
                      value={editName}
                      onChange={(e) => setEditName(e.target.value)}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                      placeholder="Task name"
                    />

                    Description
                    <textarea
                      value={editDescription}
                      onChange={(e) => setEditDescription(e.target.value)}
                      rows={3}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent resize-none"
                      placeholder="Task description"
                    />

                    Priority
                    <select
                      value={editPriority}
                      onChange={(e) => setEditPriority(Number(e.target.value))}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                    >
                      <option value={0}>Low</option>
                      <option value={1}>Medium</option>
                      <option value={2}>High</option>
                      <option value={3}>Critical</option>
                    </select>

                    <button
                      onClick={handleCancelEdit}
                      className="flex-1 px-3 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
                    >
                      Cancel
                    </button>
                    <button
                      onClick={handleSaveEdit}
                      disabled={isSaving || !editName.trim()}
                      className="flex-1 flex items-center justify-center gap-2 px-3 py-2 text-sm bg-accent hover:bg-accent/80 text-white rounded-lg transition-colors disabled:opacity-50"
                    >
                      {isSaving ? 'Saving...' : <><Check size={16} /> Save</>}
                    </button>

              ) : (
                /* View Mode */
                <>
                  {/* Task Name */}

                    Name

{selectedTask.name}

                  {/* Description */}

                    Description

                      {selectedTask.description || No description}

                  {/* Status */}

                    Status

                      {STATUS_LABELS[selectedTask.status] || selectedTask.status}

                  {/* Priority */}

                    Priority

                      {PRIORITY_LABELS[selectedTask.priority] || 'Unknown'}

                  {/* Agent Assignment */}

                      <User size={14} />
                      Agent Assignment

                      {selectedTask.agent_type ? (
                        {selectedTask.agent_type.replace('_', ' ')}
                      ) : (
                        Not assigned
                      )}

                  {/* Iteration Count */}

                      <RefreshCw size={14} />
                      Iteration Count

{selectedTask.iteration_count}

                  {/* Flagged for Review */}

                      <Flag size={14} />
                      Flagged for Review

                      {selectedTask.flagged_for_review ? 'Yes' : 'No'}

                  {/* Time Estimates */}
                  {(selectedTask.estimated_time || selectedTask.actual_time) && (

                        <Clock size={14} />
                        Time

                        {selectedTask.estimated_time &&
Estimated: {selectedTask.estimated_time} min
}
                        {selectedTask.actual_time &&
Actual: {selectedTask.actual_time} min
}

                  )}

                  {/* Created/Updated timestamps */}

Created: {new Date(selectedTask.created_at).toLocaleString()}

Updated: {new Date(selectedTask.updated_at).toLocaleString()}

                </>
              )}

        )}

        {/* Unsaved Changes Warning Dialog */}
        <AlertDialog.Root open={showUnsavedDialog} onOpenChange={setShowUnsavedDialog}>
          <AlertDialog.Portal>
            <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
            <AlertDialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">
              <AlertDialog.Title className="text-xl font-semibold text-white">
                Unsaved Changes
              </AlertDialog.Title>
              <AlertDialog.Description className="mt-3 text-slate-400">
                You have unsaved changes. Are you sure you want to discard them?
              </AlertDialog.Description>

                <AlertDialog.Cancel asChild>
                  <button
                    onClick={handleKeepEditing}
                    className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
                  >
                    Keep Editing
                  </button>
                </AlertDialog.Cancel>
                <AlertDialog.Action asChild>
                  <button
                    onClick={handleDiscardChanges}
                    className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors"
                  >
                    Discard Changes
                  </button>
                </AlertDialog.Action>

            </AlertDialog.Content>
          </AlertDialog.Portal>
        </AlertDialog.Root>

  )
}

-  const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isLoading } = useTaskStore()

+  const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isTaskDeleting, isLoading } = useTaskStore()


Now let me update the `handleDeleteTask` function to close the dialog immediately and use the store's protection:


  const handleDeleteTask = async () => {
    if (!selectedTask) return
    setIsDeleting(true)
    try {
      await deleteTask(selectedTask.id)
      setSelectedTask(null)
      setShowDeleteDialog(false)
    } catch (error) {
      console.error('Failed to delete task:', error)
    } finally {
      setIsDeleting(false)
    }
  }

  const handleDeleteTask = async () => {
    if (!selectedTask) return
    // Check if already being deleted (prevents rapid clicks)
    if (isTaskDeleting(selectedTask.id)) return

    const taskIdToDelete = selectedTask.id
    setIsDeleting(true)
    // Close dialog immediately to prevent additional clicks
    setShowDeleteDialog(false)

    try {
      await deleteTask(taskIdToDelete)
      setSelectedTask(null)
      clearTaskFromUrl()
    } catch (error) {
      console.error('Failed to delete task:', error)
      // Re-open dialog if delete failed so user can retry
      setShowDeleteDialog(true)
    } finally {
      setIsDeleting(false)
    }
  }


The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\pages\KanbanBoard.tsx has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   294→      setIsSaving(false)
   295→    }
   296→  }
   297→
   298→  const handleDeleteTask = async () => {
   299→    if (!selectedTask) return
   300→    // Check if already being deleted (prevents rapid clicks)
   301→    if (isTaskDeleting(selectedTask.id)) return
   302→
   303→    const taskIdToDelete = selectedTask.id
   304→    setIsDeleting(true)
   305→    // Close dialog immediately to prevent additional clicks
   306→    setShowDeleteDialog(false)
   307→
   308→    try {
   309→      await deleteTask(taskIdToDelete)
   310→      setSelectedTask(null)
   311→      clearTaskFromUrl()
   312→    } catch (error) {
   313→      console.error('Failed to delete task:', error)
   314→      // Re-open dialog if delete failed so user can retry
   315→      setShowDeleteDialog(true)
   316→    } finally {
   317→      setIsDeleting(false)
   318→    }
   319→  }
   320→
   321→  if (!currentProject) {
   322→    return (
   323→      <div className="flex items-center justify-center h-full">

  const handleDeleteTask = async () => {
    if (!selectedTask) return
    // Check if already being deleted (prevents rapid clicks)
    if (isTaskDeleting(selectedTask.id)) return

    const taskIdToDelete = selectedTask.id
    setIsDeleting(true)
    // Close dialog immediately to prevent additional clicks
    setShowDeleteDialog(false)

    try {
      await deleteTask(taskIdToDelete)
      setSelectedTask(null)
      clearTaskFromUrl()
    } catch (error) {
      console.error('Failed to delete task:', error)
      // Re-open dialog if delete failed so user can retry
      setShowDeleteDialog(true)
    } finally {
      setIsDeleting(false)
    }
  }

import { useEffect, useState, useMemo } from 'react'
import { useSearchParams } from 'react-router-dom'
import { Plus, X, GripVertical, Clock, User, RefreshCw, Flag, Pencil, Check, Trash2, Filter, ArrowUpDown, LayoutGrid, List, ChevronLeft, ChevronRight } from 'lucide-react'
import * as Dialog from '@radix-ui/react-dialog'
import * as AlertDialog from '@radix-ui/react-alert-dialog'
import { useProjectStore } from '../stores/projectStore'
import { useTaskStore, Task, TaskCreate, TaskUpdate } from '../stores/taskStore'

const ITEMS_PER_PAGE = 10

const COLUMNS = [
  { id: 'backlog', title: 'Backlog', color: 'border-slate-500' },
  { id: 'in_progress', title: 'In Progress', color: 'border-accent' },
  { id: 'qa', title: 'QA', color: 'border-primary-400' },
  { id: 'done', title: 'Done', color: 'border-green-400' },
  { id: 'blocked', title: 'Blocked', color: 'border-destructive' },
]

const PRIORITY_LABELS: Record<number, string> = {
  0: 'Low',
  1: 'Medium',
  2: 'High',
  3: 'Critical',
}

const STATUS_LABELS: Record<string, string> = {
  backlog: 'Backlog',
  in_progress: 'In Progress',
  qa: 'QA',
  done: 'Done',
  blocked: 'Blocked',
}

export default function KanbanBoard() {
  const [searchParams, setSearchParams] = useSearchParams()
  const { currentProject } = useProjectStore()
  const { tasks, fetchTasks, createTask, updateTask, updateTaskStatus, deleteTask, isTaskDeleting, isLoading } = useTaskStore()
  const [showAddDialog, setShowAddDialog] = useState(false)
  const [newTaskName, setNewTaskName] = useState('')
  const [newTaskDescription, setNewTaskDescription] = useState('')
  const [newTaskPriority, setNewTaskPriority] = useState(0)
  const [isCreating, setIsCreating] = useState(false)
  const [draggedTask, setDraggedTask] = useState<number | null>(null)
  const [selectedTask, setSelectedTask] = useState<Task | null>(null)
  const [isEditing, setIsEditing] = useState(false)
  const [editName, setEditName] = useState('')
  const [editDescription, setEditDescription] = useState('')
  const [editPriority, setEditPriority] = useState(0)
  const [isSaving, setIsSaving] = useState(false)
  const [showDeleteDialog, setShowDeleteDialog] = useState(false)
  const [isDeleting, setIsDeleting] = useState(false)
  const [showUnsavedDialog, setShowUnsavedDialog] = useState(false)
  const [pendingCloseAction, setPendingCloseAction] = useState<'close' | 'cancel' | null>(null)
  // Filter and Sort state - initialize from URL params
  const getInitialPriorityFilter = (): number | 'all' => {
    const param = searchParams.get('priority')
    if (param === 'all' || param === null) return 'all'
    const num = parseInt(param, 10)
    return [0, 1, 2, 3].includes(num) ? num : 'all'
  }
  const getInitialSortOrder = (): 'newest' | 'oldest' | 'priority' => {
    const param = searchParams.get('sort')
    if (param === 'newest' || param === 'oldest' || param === 'priority') return param
    return 'newest'
  }
  const getInitialViewMode = (): 'kanban' | 'list' => {
    const param = searchParams.get('view')
    if (param === 'list') return 'list'
    return 'kanban'
  }

  const [priorityFilter, setPriorityFilter] = useState<number | 'all'>(getInitialPriorityFilter)
  const [sortOrder, setSortOrder] = useState<'newest' | 'oldest' | 'priority'>(getInitialSortOrder)
  // View mode and pagination state
  const [viewMode, setViewMode] = useState<'kanban' | 'list'>(getInitialViewMode)
  const [currentPage, setCurrentPage] = useState(1)

  useEffect(() => {
    if (currentProject?.id) {
      fetchTasks(currentProject.id)
    }
  }, [currentProject?.id, fetchTasks])

  // Handle deep linking - select task from URL param after tasks are loaded
  useEffect(() => {
    const taskIdParam = searchParams.get('task')
    if (taskIdParam && tasks.length > 0) {
      const taskId = parseInt(taskIdParam, 10)
      const task = tasks.find(t => t.id === taskId)
      if (task) {
        setSelectedTask(task)
      }
    }
  }, [searchParams, tasks])

  // Update URL when task is selected
  const handleSelectTask = (task: Task) => {
    setSelectedTask(task)
    const newParams = new URLSearchParams(searchParams)
    newParams.set('task', task.id.toString())
    setSearchParams(newParams)
  }

  // Clear task from URL when panel is closed
  const clearTaskFromUrl = () => {
    const newParams = new URLSearchParams(searchParams)
    newParams.delete('task')
    setSearchParams(newParams)
  }

  // Update URL when filter changes
  const handlePriorityFilterChange = (value: number | 'all') => {
    setPriorityFilter(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'all') {
      newParams.delete('priority')
    } else {
      newParams.set('priority', value.toString())
    }
    setSearchParams(newParams)
  }

  // Update URL when sort changes
  const handleSortOrderChange = (value: 'newest' | 'oldest' | 'priority') => {
    setSortOrder(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'newest') {
      newParams.delete('sort') // default value, no need to store
    } else {
      newParams.set('sort', value)
    }
    setSearchParams(newParams)
  }

  // Update URL when view mode changes
  const handleViewModeChange = (value: 'kanban' | 'list') => {
    setViewMode(value)
    const newParams = new URLSearchParams(searchParams)
    if (value === 'kanban') {
      newParams.delete('view') // default value, no need to store
    } else {
      newParams.set('view', value)
    }
    setSearchParams(newParams)
  }

  // Filtered and sorted tasks
  const filteredAndSortedTasks = useMemo(() => {
    let result = [...tasks]

    // Apply priority filter
    if (priorityFilter !== 'all') {
      result = result.filter(task => task.priority === priorityFilter)
    }

    // Apply sort
    result.sort((a, b) => {
      if (sortOrder === 'newest') {
        return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
      } else if (sortOrder === 'oldest') {
        return new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
      } else {
        // priority - highest first
        return b.priority - a.priority
      }
    })

    return result
  }, [tasks, priorityFilter, sortOrder])

  // Pagination calculations
  const totalPages = Math.ceil(filteredAndSortedTasks.length / ITEMS_PER_PAGE)
  const paginatedTasks = useMemo(() => {
    const startIndex = (currentPage - 1) * ITEMS_PER_PAGE
    return filteredAndSortedTasks.slice(startIndex, startIndex + ITEMS_PER_PAGE)
  }, [filteredAndSortedTasks, currentPage])

  // Reset page when filter changes
  useEffect(() => {
    setCurrentPage(1)
  }, [priorityFilter, sortOrder])

  const getTasksByStatus = (status: string) => {
    return filteredAndSortedTasks.filter((task) => task.status === status)
  }

  const handleCreateTask = async () => {
    if (!currentProject || !newTaskName.trim()) return
    setIsCreating(true)
    try {
      const taskData: TaskCreate = {
        name: newTaskName.trim(),
        description: newTaskDescription.trim() || undefined,
        priority: newTaskPriority,
      }
      await createTask(currentProject.id, taskData)
      setNewTaskName('')
      setNewTaskDescription('')
      setNewTaskPriority(0)
      setShowAddDialog(false)
    } catch (error) {
      console.error('Failed to create task:', error)
    } finally {
      setIsCreating(false)
    }
  }

  const handleDragStart = (taskId: number) => {
    setDraggedTask(taskId)
  }

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault()
  }

  const handleDrop = async (targetStatus: string) => {
    if (draggedTask === null) return
    try {
      await updateTaskStatus(draggedTask, targetStatus)
    } catch (error) {
      console.error('Failed to update task status:', error)
    }
    setDraggedTask(null)
  }

  const handleStartEdit = () => {
    if (!selectedTask) return
    setEditName(selectedTask.name)
    setEditDescription(selectedTask.description || '')
    setEditPriority(selectedTask.priority)
    setIsEditing(true)
  }

  // Check if edit form has unsaved changes
  const hasUnsavedChanges = () => {
    if (!selectedTask || !isEditing) return false
    return (
      editName.trim() !== selectedTask.name ||
      (editDescription.trim() || '') !== (selectedTask.description || '') ||
      editPriority !== selectedTask.priority
    )
  }

  const handleCancelEdit = () => {
    if (hasUnsavedChanges()) {
      setPendingCloseAction('cancel')
      setShowUnsavedDialog(true)
    } else {
      setIsEditing(false)
    }
  }

  const handleClosePanel = () => {
    if (hasUnsavedChanges()) {
      setPendingCloseAction('close')
      setShowUnsavedDialog(true)
    } else {
      setSelectedTask(null)
      setIsEditing(false)
      clearTaskFromUrl()
    }
  }

  const handleDiscardChanges = () => {
    setShowUnsavedDialog(false)
    if (pendingCloseAction === 'close') {
      setSelectedTask(null)
      clearTaskFromUrl()
    }
    setIsEditing(false)
    setPendingCloseAction(null)
  }

  const handleKeepEditing = () => {
    setShowUnsavedDialog(false)
    setPendingCloseAction(null)
  }

  const handleSaveEdit = async () => {
    if (!selectedTask) return
    setIsSaving(true)
    try {
      const updates: TaskUpdate = {
        name: editName.trim(),
        description: editDescription.trim() || undefined,
        priority: editPriority,
      }
      const updatedTask = await updateTask(selectedTask.id, updates)
      setSelectedTask(updatedTask)
      setIsEditing(false)
    } catch (error) {
      console.error('Failed to update task:', error)
    } finally {
      setIsSaving(false)
    }
  }

  const handleDeleteTask = async () => {
    if (!selectedTask) return
    setIsDeleting(true)
    try {
      await deleteTask(selectedTask.id)
      setSelectedTask(null)
      setShowDeleteDialog(false)
    } catch (error) {
      console.error('Failed to delete task:', error)
    } finally {
      setIsDeleting(false)
    }
  }

  if (!currentProject) {
    return (

Select a project to view its Kanban board

    )
  }

  return (

      {/* Header */}

Kanban Board

          {/* Priority Filter */}

            <Filter size={16} className="text-slate-400" />
            <select
              value={priorityFilter === 'all' ? 'all' : priorityFilter.toString()}
              onChange={(e) => handlePriorityFilterChange(e.target.value === 'all' ? 'all' : Number(e.target.value))}
              className="px-3 py-1.5 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-accent"
            >
              <option value="all">All Priorities</option>
              <option value="3">Critical</option>
              <option value="2">High</option>
              <option value="1">Medium</option>
              <option value="0">Low</option>
            </select>

          {/* Sort Order */}

            <ArrowUpDown size={16} className="text-slate-400" />
            <select
              value={sortOrder}
              onChange={(e) => handleSortOrderChange(e.target.value as 'newest' | 'oldest' | 'priority')}
              className="px-3 py-1.5 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-accent"
            >
              <option value="newest">Newest First</option>
              <option value="oldest">Oldest First</option>
              <option value="priority">By Priority</option>
            </select>

          {/* View Mode Toggle */}

            <button
              onClick={() => handleViewModeChange('kanban')}
              className={`p-1.5 rounded ${viewMode === 'kanban' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
              title="Kanban View"
            >
              <LayoutGrid size={18} />
            </button>
            <button
              onClick={() => handleViewModeChange('list')}
              className={`p-1.5 rounded ${viewMode === 'list' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
              title="List View"
            >
              <List size={18} />
            </button>

        <Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
          <Dialog.Trigger asChild>
            <button className="btn-accent flex items-center gap-2">
              <Plus size={18} />
              Add Task
            </button>
          </Dialog.Trigger>
          <Dialog.Portal>
            <Dialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
            <Dialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">

                <Dialog.Title className="text-xl font-semibold text-white">
                  Add New Task
                </Dialog.Title>
                <Dialog.Close asChild>
                  <button className="text-slate-400 hover:text-white">
                    <X size={20} />
                  </button>
                </Dialog.Close>

              <Dialog.Description className="text-slate-400 mb-4">
                Create a new task for this project.
              </Dialog.Description>

                    Task Name *

                  <input
                    type="text"
                    value={newTaskName}
                    onChange={(e) => setNewTaskName(e.target.value)}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                    placeholder="Enter task name"
                  />

                    Description

                  <textarea
                    value={newTaskDescription}
                    onChange={(e) => setNewTaskDescription(e.target.value)}
                    rows={3}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent resize-none"
                    placeholder="Enter task description"
                  />

                    Priority

                  <select
                    value={newTaskPriority}
                    onChange={(e) => setNewTaskPriority(Number(e.target.value))}
                    className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                  >
                    <option value={0}>Low</option>
                    <option value={1}>Medium</option>
                    <option value={2}>High</option>
                    <option value={3}>Critical</option>
                  </select>

                <Dialog.Close asChild>
                  <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
                    Cancel
                  </button>
                </Dialog.Close>
                <button
                  onClick={handleCreateTask}
                  disabled={isCreating || !newTaskName.trim()}
                  className="px-4 py-2 text-sm bg-accent hover:bg-accent/80 text-white rounded-lg transition-colors disabled:opacity-50"
                >
                  {isCreating ? 'Creating...' : 'Create Task'}
                </button>

            </Dialog.Content>
          </Dialog.Portal>
        </Dialog.Root>

      {/* Main Content Area */}

        {viewMode === 'list' ? (
          /* List View with Pagination */

            {/* Task List Table */}

                    Task Name
                    Status
                    Priority
                    Created

                  {isLoading && tasks.length === 0 ? (

                        Loading...

                  ) : paginatedTasks.length === 0 ? (

                        No tasks found

                  ) : (
                    paginatedTasks.map((task) => (

 handleSelectTask(task)}
                        className={`border-t border-slate-700 hover:bg-slate-700/50 cursor-pointer ${
                          selectedTask?.id === task.id ? 'bg-slate-700' : ''
                        }`}
                      >

{task.name}

                          {task.description && (

                              {task.description}

                          )}

                            {STATUS_LABELS[task.status] || task.status}

                            {PRIORITY_LABELS[task.priority] || 'Unknown'}

                          {new Date(task.created_at).toLocaleDateString()}

                    ))
                  )}

            {/* Pagination Controls */}
            {totalPages > 1 && (

                  Showing {((currentPage - 1) * ITEMS_PER_PAGE) + 1} to {Math.min(currentPage * ITEMS_PER_PAGE, filteredAndSortedTasks.length)} of {filteredAndSortedTasks.length} tasks

                  <button
                    onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
                    disabled={currentPage === 1}
                    className="p-2 rounded-lg bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    <ChevronLeft size={18} />
                  </button>

                    {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
                      <button
                        key={page}
                        onClick={() => setCurrentPage(page)}
                        className={`w-8 h-8 rounded-lg text-sm ${
                          page === currentPage
                            ? 'bg-accent text-white'
                            : 'bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700'
                        }`}
                      >
                        {page}
                      </button>
                    ))}

                  <button
                    onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
                    disabled={currentPage === totalPages}
                    className="p-2 rounded-lg bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700 disabled:opacity-50 disabled:cursor-not-allowed"
                  >
                    <ChevronRight size={18} />
                  </button>

            )}

        ) : (
        /* Kanban Columns */
        <div className={`flex-1 flex gap-4 overflow-x-auto pb-4 ${selectedTask ? 'mr-0' : ''}`}>
          {COLUMNS.map((column) => (
          <div
            key={column.id}
            className={`flex-shrink-0 w-72 bg-slate-800 rounded-lg border-t-2 ${column.color}`}
            onDragOver={handleDragOver}
            onDrop={() => handleDrop(column.id)}
          >
            {/* Column Header */}

{column.title}

                  {getTasksByStatus(column.id).length}

            {/* Column Content */}

              {isLoading && tasks.length === 0 ? (

                  Loading...

              ) : getTasksByStatus(column.id).length === 0 ? (

                  No tasks

              ) : (
                getTasksByStatus(column.id).map((task) => (

 handleDragStart(task.id)}
                    onClick={() => handleSelectTask(task)}
                    className={`kanban-card bg-slate-900 rounded-lg p-4 border border-slate-700 cursor-pointer hover:border-slate-600 ${
                      draggedTask === task.id ? 'opacity-50' : ''
                    } ${selectedTask?.id === task.id ? 'ring-2 ring-accent' : ''}`}
                  >

                      <GripVertical size={16} className="text-slate-600 mt-0.5 flex-shrink-0" />

{task.name}

                        {task.description && (

                            {task.description}

                        )}

                          <span
                            className={`badge ${
                              column.id === 'backlog'
                                ? 'badge-backlog'
                                : column.id === 'in_progress'
                                ? 'badge-in-progress'
                                : column.id === 'qa'
                                ? 'badge-qa'
                                : column.id === 'done'
                                ? 'badge-done'
                                : 'badge-blocked'
                            }`}
                          >
                            {column.title}

                            {task.priority === 3 ? 'Critical' :
                             task.priority === 2 ? 'High' :
                             task.priority === 1 ? 'Medium' : 'Low'}

                ))
              )}

          ))}

        )}

        {/* Task Details Panel */}
        {selectedTask && (

Task Details

                {!isEditing && (
                  <>
                    <button
                      onClick={handleStartEdit}
                      className="text-slate-400 hover:text-accent transition-colors"
                      title="Edit Task"
                    >
                      <Pencil size={18} />
                    </button>
                    <AlertDialog.Root open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
                      <AlertDialog.Trigger asChild>
                        <button
                          className="text-slate-400 hover:text-destructive transition-colors"
                          title="Delete Task"
                        >
                          <Trash2 size={18} />
                        </button>
                      </AlertDialog.Trigger>
                      <AlertDialog.Portal>
                        <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
                        <AlertDialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">
                          <AlertDialog.Title className="text-xl font-semibold text-white">
                            Delete Task
                          </AlertDialog.Title>
                          <AlertDialog.Description className="mt-3 text-slate-400">
                            Are you sure you want to delete {selectedTask.name}?
                            This action cannot be undone.
                          </AlertDialog.Description>

                            <AlertDialog.Cancel asChild>
                              <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
                                Cancel
                              </button>
                            </AlertDialog.Cancel>
                            <AlertDialog.Action asChild>
                              <button
                                onClick={handleDeleteTask}
                                disabled={isDeleting}
                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
                              >
                                {isDeleting ? 'Deleting...' : 'Delete Task'}
                              </button>
                            </AlertDialog.Action>

                        </AlertDialog.Content>
                      </AlertDialog.Portal>
                    </AlertDialog.Root>
                  </>
                )}
                <button
                  onClick={handleClosePanel}
                  className="text-slate-400 hover:text-white transition-colors"
                  title="Close"
                >
                  <X size={20} />
                </button>

              {isEditing ? (
                /* Edit Form */

                    Name *
                    <input
                      type="text"
                      value={editName}
                      onChange={(e) => setEditName(e.target.value)}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                      placeholder="Task name"
                    />

                    Description
                    <textarea
                      value={editDescription}
                      onChange={(e) => setEditDescription(e.target.value)}
                      rows={3}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent resize-none"
                      placeholder="Task description"
                    />

                    Priority
                    <select
                      value={editPriority}
                      onChange={(e) => setEditPriority(Number(e.target.value))}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                    >
                      <option value={0}>Low</option>
                      <option value={1}>Medium</option>
                      <option value={2}>High</option>
                      <option value={3}>Critical</option>
                    </select>

                    <button
                      onClick={handleCancelEdit}
                      className="flex-1 px-3 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
                    >
                      Cancel
                    </button>
                    <button
                      onClick={handleSaveEdit}
                      disabled={isSaving || !editName.trim()}
                      className="flex-1 flex items-center justify-center gap-2 px-3 py-2 text-sm bg-accent hover:bg-accent/80 text-white rounded-lg transition-colors disabled:opacity-50"
                    >
                      {isSaving ? 'Saving...' : <><Check size={16} /> Save</>}
                    </button>

              ) : (
                /* View Mode */
                <>
                  {/* Task Name */}

                    Name

{selectedTask.name}

                  {/* Description */}

                    Description

                      {selectedTask.description || No description}

                  {/* Status */}

                    Status

                      {STATUS_LABELS[selectedTask.status] || selectedTask.status}

                  {/* Priority */}

                    Priority

                      {PRIORITY_LABELS[selectedTask.priority] || 'Unknown'}

                  {/* Agent Assignment */}

                      <User size={14} />
                      Agent Assignment

                      {selectedTask.agent_type ? (
                        {selectedTask.agent_type.replace('_', ' ')}
                      ) : (
                        Not assigned
                      )}

                  {/* Iteration Count */}

                      <RefreshCw size={14} />
                      Iteration Count

{selectedTask.iteration_count}

                  {/* Flagged for Review */}

                      <Flag size={14} />
                      Flagged for Review

                      {selectedTask.flagged_for_review ? 'Yes' : 'No'}

                  {/* Time Estimates */}
                  {(selectedTask.estimated_time || selectedTask.actual_time) && (

                        <Clock size={14} />
                        Time

                        {selectedTask.estimated_time &&
Estimated: {selectedTask.estimated_time} min
}
                        {selectedTask.actual_time &&
Actual: {selectedTask.actual_time} min
}

                  )}

                  {/* Created/Updated timestamps */}

Created: {new Date(selectedTask.created_at).toLocaleString()}

Updated: {new Date(selectedTask.updated_at).toLocaleString()}

                </>
              )}

        )}

        {/* Unsaved Changes Warning Dialog */}
        <AlertDialog.Root open={showUnsavedDialog} onOpenChange={setShowUnsavedDialog}>
          <AlertDialog.Portal>
            <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
            <AlertDialog.Content className="fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-slate-800 border border-slate-700 rounded-lg p-6 w-full max-w-md z-50 shadow-xl">
              <AlertDialog.Title className="text-xl font-semibold text-white">
                Unsaved Changes
              </AlertDialog.Title>
              <AlertDialog.Description className="mt-3 text-slate-400">
                You have unsaved changes. Are you sure you want to discard them?
              </AlertDialog.Description>

                <AlertDialog.Cancel asChild>
                  <button
                    onClick={handleKeepEditing}
                    className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
                  >
                    Keep Editing
                  </button>
                </AlertDialog.Cancel>
                <AlertDialog.Action asChild>
                  <button
                    onClick={handleDiscardChanges}
                    className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors"
                  >
                    Discard Changes
                  </button>
                </AlertDialog.Action>

            </AlertDialog.Content>
          </AlertDialog.Portal>
        </AlertDialog.Root>

  )
}

+    // Check if already being deleted (prevents rapid clicks)

+    if (isTaskDeleting(selectedTask.id)) return

+    const taskIdToDelete = selectedTask.id

+    // Close dialog immediately to prevent additional clicks

-      await deleteTask(selectedTask.id)

+      // Re-open dialog if delete failed so user can retry


Now let me also update the delete button in the dialog to check the store's isTaskDeleting:


700→                            Delete Task
   701→                          </AlertDialog.Title>
   702→                          <AlertDialog.Description className="mt-3 text-slate-400">
   703→                            Are you sure you want to delete {selectedTask.name}?
   704→                            This action cannot be undone.
   705→                          </AlertDialog.Description>
   706→

   707→                            <AlertDialog.Cancel asChild>
   708→                              <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
   709→                                Cancel
   710→                              </button>
   711→                            </AlertDialog.Cancel>
   712→                            <AlertDialog.Action asChild>
   713→                              <button
   714→                                onClick={handleDeleteTask}
   715→                                disabled={isDeleting}
   716→                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
   717→                              >
   718→                                {isDeleting ? 'Deleting...' : 'Delete Task'}
   719→                              </button>
   720→                            </AlertDialog.Action>
   721→

   722→                        </AlertDialog.Content>
   723→                      </AlertDialog.Portal>
   724→                    </AlertDialog.Root>
   725→                  </>
   726→                )}
   727→                <button
   728→                  onClick={handleClosePanel}
   729→                  className="text-slate-400 hover:text-white transition-colors"
   730→                  title="Close"
   731→                >
   732→                  <X size={20} />
   733→                </button>
   734→

   735→

   736→

   737→              {isEditing ? (
   738→                /* Edit Form */
   739→

   740→

   741→                    Name *
   742→                    <input
   743→                      type="text"
   744→                      value={editName}
   745→                      onChange={(e) => setEditName(e.target.value)}
   746→                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
   747→                      placeholder="Task name"
   748→                    />
   749→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

Delete Task
                          </AlertDialog.Title>
                          <AlertDialog.Description className="mt-3 text-slate-400">
                            Are you sure you want to delete {selectedTask.name}?
                            This action cannot be undone.
                          </AlertDialog.Description>

                            <AlertDialog.Cancel asChild>
                              <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
                                Cancel
                              </button>
                            </AlertDialog.Cancel>
                            <AlertDialog.Action asChild>
                              <button
                                onClick={handleDeleteTask}
                                disabled={isDeleting}
                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
                              >
                                {isDeleting ? 'Deleting...' : 'Delete Task'}
                              </button>
                            </AlertDialog.Action>

                        </AlertDialog.Content>
                      </AlertDialog.Portal>
                    </AlertDialog.Root>
                  </>
                )}
                <button
                  onClick={handleClosePanel}
                  className="text-slate-400 hover:text-white transition-colors"
                  title="Close"
                >
                  <X size={20} />
                </button>

              {isEditing ? (
                /* Edit Form */

                    Name *
                    <input
                      type="text"
                      value={editName}
                      onChange={(e) => setEditName(e.target.value)}
                      className="w-full px-3 py-2 bg-slate-900 border border-slate-700 rounded-lg text-white placeholder-slate-500 focus:outline-none focus:ring-2 focus:ring-accent focus:border-transparent"
                      placeholder="Task name"
                    />


Let me update the delete button to also check the store's isTaskDeleting:


                            <AlertDialog.Action asChild>
                              <button
                                onClick={handleDeleteTask}
                                disabled={isDeleting}
                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
                              >
                                {isDeleting ? 'Deleting...' : 'Delete Task'}
                              </button>
                            </AlertDialog.Action>

                            <AlertDialog.Action asChild>
                              <button
                                onClick={handleDeleteTask}
                                disabled={isDeleting || (selectedTask ? isTaskDeleting(selectedTask.id) : false)}
                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
                              >
                                {isDeleting || (selectedTask && isTaskDeleting(selectedTask.id)) ? 'Deleting...' : 'Delete Task'}
                              </button>
                            </AlertDialog.Action>