1→import { useEffect, useState, useMemo } from 'react'
     2→import { useSearchParams } from 'react-router-dom'
     3→import { Plus, X, GripVertical, Clock, User, RefreshCw, Flag, Pencil, Check, Trash2, Filter, ArrowUpDown, LayoutGrid, List, ChevronLeft, ChevronRight } from 'lucide-react'
     4→import * as Dialog from '@radix-ui/react-dialog'
     5→import * as AlertDialog from '@radix-ui/react-alert-dialog'
     6→import { useProjectStore } from '../stores/projectStore'
     7→import { useTaskStore, Task, TaskCreate, TaskUpdate } from '../stores/taskStore'
     8→
     9→const ITEMS_PER_PAGE = 10
    10→
    11→const COLUMNS = [
    12→  { id: 'backlog', title: 'Backlog', color: 'border-slate-500' },
    13→  { id: 'in_progress', title: 'In Progress', color: 'border-accent' },
    14→  { id: 'qa', title: 'QA', color: 'border-primary-400' },
    15→  { id: 'done', title: 'Done', color: 'border-green-400' },
    16→  { id: 'blocked', title: 'Blocked', color: 'border-destructive' },
    17→]
    18→
    19→const PRIORITY_LABELS: Record<number, string> = {
    20→  0: 'Low',
    21→  1: 'Medium',
    22→  2: 'High',
    23→  3: 'Critical',
    24→}
    25→
    26→const STATUS_LABELS: Record<string, string> = {
    27→  backlog: 'Backlog',
    28→  in_progress: 'In Progress',
    29→  qa: 'QA',
    30→  done: 'Done',
    31→  blocked: 'Blocked',
    32→}
    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)
    42→  const [isCreating, setIsCreating] = useState(false)
    43→  const [draggedTask, setDraggedTask] = useState<number | null>(null)
    44→  const [selectedTask, setSelectedTask] = useState<Task | null>(null)
    45→  const [isEditing, setIsEditing] = useState(false)
    46→  const [editName, setEditName] = useState('')
    47→  const [editDescription, setEditDescription] = useState('')
    48→  const [editPriority, setEditPriority] = useState(0)
    49→  const [isSaving, setIsSaving] = useState(false)
    50→  const [showDeleteDialog, setShowDeleteDialog] = useState(false)
    51→  const [isDeleting, setIsDeleting] = useState(false)
    52→  const [showUnsavedDialog, setShowUnsavedDialog] = useState(false)
    53→  const [pendingCloseAction, setPendingCloseAction] = useState<'close' | 'cancel' | null>(null)
    54→  // Filter and Sort state - initialize from URL params
    55→  const getInitialPriorityFilter = (): number | 'all' => {
    56→    const param = searchParams.get('priority')
    57→    if (param === 'all' || param === null) return 'all'
    58→    const num = parseInt(param, 10)
    59→    return [0, 1, 2, 3].includes(num) ? num : 'all'
    60→  }
    61→  const getInitialSortOrder = (): 'newest' | 'oldest' | 'priority' => {
    62→    const param = searchParams.get('sort')
    63→    if (param === 'newest' || param === 'oldest' || param === 'priority') return param
    64→    return 'newest'
    65→  }
    66→  const getInitialViewMode = (): 'kanban' | 'list' => {
    67→    const param = searchParams.get('view')
    68→    if (param === 'list') return 'list'
    69→    return 'kanban'
    70→  }
    71→
    72→  const [priorityFilter, setPriorityFilter] = useState<number | 'all'>(getInitialPriorityFilter)
    73→  const [sortOrder, setSortOrder] = useState<'newest' | 'oldest' | 'priority'>(getInitialSortOrder)
    74→  // View mode and pagination state
    75→  const [viewMode, setViewMode] = useState<'kanban' | 'list'>(getInitialViewMode)
    76→  const [currentPage, setCurrentPage] = useState(1)
    77→
    78→  useEffect(() => {
    79→    if (currentProject?.id) {
    80→      fetchTasks(currentProject.id)
    81→    }
    82→  }, [currentProject?.id, fetchTasks])
    83→
    84→  // Handle deep linking - select task from URL param after tasks are loaded
    85→  useEffect(() => {
    86→    const taskIdParam = searchParams.get('task')
    87→    if (taskIdParam && tasks.length > 0) {
    88→      const taskId = parseInt(taskIdParam, 10)
    89→      const task = tasks.find(t => t.id === taskId)
    90→      if (task) {
    91→        setSelectedTask(task)
    92→      }
    93→    }
    94→  }, [searchParams, tasks])
    95→
    96→  // Update URL when task is selected
    97→  const handleSelectTask = (task: Task) => {
    98→    setSelectedTask(task)
    99→    const newParams = new URLSearchParams(searchParams)
   100→    newParams.set('task', task.id.toString())
   101→    setSearchParams(newParams)
   102→  }
   103→
   104→  // Clear task from URL when panel is closed
   105→  const clearTaskFromUrl = () => {
   106→    const newParams = new URLSearchParams(searchParams)
   107→    newParams.delete('task')
   108→    setSearchParams(newParams)
   109→  }
   110→
   111→  // Update URL when filter changes
   112→  const handlePriorityFilterChange = (value: number | 'all') => {
   113→    setPriorityFilter(value)
   114→    const newParams = new URLSearchParams(searchParams)
   115→    if (value === 'all') {
   116→      newParams.delete('priority')
   117→    } else {
   118→      newParams.set('priority', value.toString())
   119→    }
   120→    setSearchParams(newParams)
   121→  }
   122→
   123→  // Update URL when sort changes
   124→  const handleSortOrderChange = (value: 'newest' | 'oldest' | 'priority') => {
   125→    setSortOrder(value)
   126→    const newParams = new URLSearchParams(searchParams)
   127→    if (value === 'newest') {
   128→      newParams.delete('sort') // default value, no need to store
   129→    } else {
   130→      newParams.set('sort', value)
   131→    }
   132→    setSearchParams(newParams)
   133→  }
   134→
   135→  // Update URL when view mode changes
   136→  const handleViewModeChange = (value: 'kanban' | 'list') => {
   137→    setViewMode(value)
   138→    const newParams = new URLSearchParams(searchParams)
   139→    if (value === 'kanban') {
   140→      newParams.delete('view') // default value, no need to store
   141→    } else {
   142→      newParams.set('view', value)
   143→    }
   144→    setSearchParams(newParams)
   145→  }
   146→
   147→  // Reset all filters to defaults
   148→  const handleResetFilters = () => {
   149→    setPriorityFilter('all')
   150→    setSortOrder('newest')
   151→    setCurrentPage(1)
   152→    const newParams = new URLSearchParams(searchParams)
   153→    newParams.delete('priority')
   154→    newParams.delete('sort')
   155→    setSearchParams(newParams)
   156→  }
   157→
   158→  // Check if filters are active (non-default)
   159→  const hasActiveFilters = priorityFilter !== 'all' || sortOrder !== 'newest'
   160→
   161→  // Filtered and sorted tasks
   162→  const filteredAndSortedTasks = useMemo(() => {
   163→    let result = [...tasks]
   164→
   165→    // Apply priority filter
   166→    if (priorityFilter !== 'all') {
   167→      result = result.filter(task => task.priority === priorityFilter)
   168→    }
   169→
   170→    // Apply sort
   171→    result.sort((a, b) => {
   172→      if (sortOrder === 'newest') {
   173→        return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
   174→      } else if (sortOrder === 'oldest') {
   175→        return new Date(a.created_at).getTime() - new Date(b.created_at).getTime()
   176→      } else {
   177→        // priority - highest first
   178→        return b.priority - a.priority
   179→      }
   180→    })
   181→
   182→    return result
   183→  }, [tasks, priorityFilter, sortOrder])
   184→
   185→  // Pagination calculations
   186→  const totalPages = Math.ceil(filteredAndSortedTasks.length / ITEMS_PER_PAGE)
   187→  const paginatedTasks = useMemo(() => {
   188→    const startIndex = (currentPage - 1) * ITEMS_PER_PAGE
   189→    return filteredAndSortedTasks.slice(startIndex, startIndex + ITEMS_PER_PAGE)
   190→  }, [filteredAndSortedTasks, currentPage])
   191→
   192→  // Reset page when filter changes
   193→  useEffect(() => {
   194→    setCurrentPage(1)
   195→  }, [priorityFilter, sortOrder])
   196→
   197→  const getTasksByStatus = (status: string) => {
   198→    return filteredAndSortedTasks.filter((task) => task.status === status)
   199→  }
   200→
   201→  const handleCreateTask = async () => {
   202→    if (!currentProject || !newTaskName.trim()) return
   203→    setIsCreating(true)
   204→    try {
   205→      const taskData: TaskCreate = {
   206→        name: newTaskName.trim(),
   207→        description: newTaskDescription.trim() || undefined,
   208→        priority: newTaskPriority,
   209→      }
   210→      await createTask(currentProject.id, taskData)
   211→      setNewTaskName('')
   212→      setNewTaskDescription('')
   213→      setNewTaskPriority(0)
   214→      setShowAddDialog(false)
   215→    } catch (error) {
   216→      console.error('Failed to create task:', error)
   217→    } finally {
   218→      setIsCreating(false)
   219→    }
   220→  }
   221→
   222→  const handleDragStart = (taskId: number) => {
   223→    setDraggedTask(taskId)
   224→  }
   225→
   226→  const handleDragOver = (e: React.DragEvent) => {
   227→    e.preventDefault()
   228→  }
   229→
   230→  const handleDrop = async (targetStatus: string) => {
   231→    if (draggedTask === null) return
   232→    try {
   233→      await updateTaskStatus(draggedTask, targetStatus)
   234→    } catch (error) {
   235→      console.error('Failed to update task status:', error)
   236→    }
   237→    setDraggedTask(null)
   238→  }
   239→
   240→  const handleStartEdit = () => {
   241→    if (!selectedTask) return
   242→    setEditName(selectedTask.name)
   243→    setEditDescription(selectedTask.description || '')
   244→    setEditPriority(selectedTask.priority)
   245→    setIsEditing(true)
   246→  }
   247→
   248→  // Check if edit form has unsaved changes
   249→  const hasUnsavedChanges = () => {
   250→    if (!selectedTask || !isEditing) return false
   251→    return (
   252→      editName.trim() !== selectedTask.name ||
   253→      (editDescription.trim() || '') !== (selectedTask.description || '') ||
   254→      editPriority !== selectedTask.priority
   255→    )
   256→  }
   257→
   258→  const handleCancelEdit = () => {
   259→    if (hasUnsavedChanges()) {
   260→      setPendingCloseAction('cancel')
   261→      setShowUnsavedDialog(true)
   262→    } else {
   263→      setIsEditing(false)
   264→    }
   265→  }
   266→
   267→  const handleClosePanel = () => {
   268→    if (hasUnsavedChanges()) {
   269→      setPendingCloseAction('close')
   270→      setShowUnsavedDialog(true)
   271→    } else {
   272→      setSelectedTask(null)
   273→      setIsEditing(false)
   274→      clearTaskFromUrl()
   275→    }
   276→  }
   277→
   278→  const handleDiscardChanges = () => {
   279→    setShowUnsavedDialog(false)
   280→    if (pendingCloseAction === 'close') {
   281→      setSelectedTask(null)
   282→      clearTaskFromUrl()
   283→    }
   284→    setIsEditing(false)
   285→    setPendingCloseAction(null)
   286→  }
   287→
   288→  const handleKeepEditing = () => {
   289→    setShowUnsavedDialog(false)
   290→    setPendingCloseAction(null)
   291→  }
   292→
   293→  const handleSaveEdit = async () => {
   294→    if (!selectedTask) return
   295→    setIsSaving(true)
   296→    try {
   297→      const updates: TaskUpdate = {
   298→        name: editName.trim(),
   299→        description: editDescription.trim() || undefined,
   300→        priority: editPriority,
   301→      }
   302→      const updatedTask = await updateTask(selectedTask.id, updates)
   303→      setSelectedTask(updatedTask)
   304→      setIsEditing(false)
   305→    } catch (error) {
   306→      console.error('Failed to update task:', error)
   307→    } finally {
   308→      setIsSaving(false)
   309→    }
   310→  }
   311→
   312→  const handleDeleteTask = async () => {
   313→    if (!selectedTask) return
   314→    // Check if already being deleted (prevents rapid clicks)
   315→    if (isTaskDeleting(selectedTask.id)) return
   316→
   317→    const taskIdToDelete = selectedTask.id
   318→    setIsDeleting(true)
   319→    // Close dialog immediately to prevent additional clicks
   320→    setShowDeleteDialog(false)
   321→
   322→    try {
   323→      await deleteTask(taskIdToDelete)
   324→      setSelectedTask(null)
   325→      clearTaskFromUrl()
   326→    } catch (error) {
   327→      console.error('Failed to delete task:', error)
   328→      // Re-open dialog if delete failed so user can retry
   329→      setShowDeleteDialog(true)
   330→    } finally {
   331→      setIsDeleting(false)
   332→    }
   333→  }
   334→
   335→  if (!currentProject) {
   336→    return (
   337→

   338→
Select a project to view its Kanban board

   339→

   340→    )
   341→  }
   342→
   343→  return (
   344→

   345→      {/* Header */}
   346→

   347→
Kanban Board

   348→

   349→          {/* Priority Filter */}
   350→

   351→            <Filter size={16} className="text-slate-400" />
   352→            <select
   353→              value={priorityFilter === 'all' ? 'all' : priorityFilter.toString()}
   354→              onChange={(e) => handlePriorityFilterChange(e.target.value === 'all' ? 'all' : Number(e.target.value))}
   355→              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"
   356→            >
   357→              <option value="all">All Priorities</option>
   358→              <option value="3">Critical</option>
   359→              <option value="2">High</option>
   360→              <option value="1">Medium</option>
   361→              <option value="0">Low</option>
   362→            </select>
   363→

   364→
   365→          {/* Sort Order */}
   366→

   367→            <ArrowUpDown size={16} className="text-slate-400" />
   368→            <select
   369→              value={sortOrder}
   370→              onChange={(e) => handleSortOrderChange(e.target.value as 'newest' | 'oldest' | 'priority')}
   371→              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"
   372→            >
   373→              <option value="newest">Newest First</option>
   374→              <option value="oldest">Oldest First</option>
   375→              <option value="priority">By Priority</option>
   376→            </select>
   377→

   378→
   379→          {/* Reset Filters Button */}
   380→          {hasActiveFilters && (
   381→            <button
   382→              onClick={handleResetFilters}
   383→              className="flex items-center gap-1.5 px-3 py-1.5 text-sm text-slate-400 hover:text-white hover:bg-slate-700 rounded-lg transition-colors"
   384→              title="Reset Filters"
   385→            >
   386→              <RefreshCw size={14} />
   387→              Reset
   388→            </button>
   389→          )}
   390→
   391→          {/* View Mode Toggle */}
   392→

   393→            <button
   394→              onClick={() => handleViewModeChange('kanban')}
   395→              className={`p-1.5 rounded ${viewMode === 'kanban' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
   396→              title="Kanban View"
   397→            >
   398→              <LayoutGrid size={18} />
   399→            </button>
   400→            <button
   401→              onClick={() => handleViewModeChange('list')}
   402→              className={`p-1.5 rounded ${viewMode === 'list' ? 'bg-accent text-white' : 'text-slate-400 hover:text-white'}`}
   403→              title="List View"
   404→            >
   405→              <List size={18} />
   406→            </button>
   407→

   408→
   409→        <Dialog.Root open={showAddDialog} onOpenChange={setShowAddDialog}>
   410→          <Dialog.Trigger asChild>
   411→            <button className="btn-accent flex items-center gap-2">
   412→              <Plus size={18} />
   413→              Add Task
   414→            </button>
   415→          </Dialog.Trigger>
   416→          <Dialog.Portal>
   417→            <Dialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
   418→            <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">
   419→

   420→                <Dialog.Title className="text-xl font-semibold text-white">
   421→                  Add New Task
   422→                </Dialog.Title>
   423→                <Dialog.Close asChild>
   424→                  <button className="text-slate-400 hover:text-white">
   425→                    <X size={20} />
   426→                  </button>
   427→                </Dialog.Close>
   428→

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

   433→

   434→
   435→                    Task Name *
   436→
   437→                  <input
   438→                    type="text"
   439→                    value={newTaskName}
   440→                    onChange={(e) => setNewTaskName(e.target.value)}
   441→                    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"
   442→                    placeholder="Enter task name"
   443→                  />
   444→

   445→

   446→
   447→                    Description
   448→
   449→                  <textarea
   450→                    value={newTaskDescription}
   451→                    onChange={(e) => setNewTaskDescription(e.target.value)}
   452→                    rows={3}
   453→                    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"
   454→                    placeholder="Enter task description"
   455→                  />
   456→

   457→

   458→
   459→                    Priority
   460→
   461→                  <select
   462→                    value={newTaskPriority}
   463→                    onChange={(e) => setNewTaskPriority(Number(e.target.value))}
   464→                    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"
   465→                  >
   466→                    <option value={0}>Low</option>
   467→                    <option value={1}>Medium</option>
   468→                    <option value={2}>High</option>
   469→                    <option value={3}>Critical</option>
   470→                  </select>
   471→

   472→

   473→

   474→                <Dialog.Close asChild>
   475→                  <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
   476→                    Cancel
   477→                  </button>
   478→                </Dialog.Close>
   479→                <button
   480→                  onClick={handleCreateTask}
   481→                  disabled={isCreating || !newTaskName.trim()}
   482→                  className="px-4 py-2 text-sm bg-accent hover:bg-accent/80 text-white rounded-lg transition-colors disabled:opacity-50"
   483→                >
   484→                  {isCreating ? 'Creating...' : 'Create Task'}
   485→                </button>
   486→

   487→            </Dialog.Content>
   488→          </Dialog.Portal>
   489→        </Dialog.Root>
   490→

   491→

   492→
   493→      {/* Main Content Area */}
   494→

   495→        {viewMode === 'list' ? (
   496→          /* List View with Pagination */
   497→

   498→            {/* Task List Table */}
   499→

   500→

   501→

   502→

   503→                    Task Name
   504→                    Status
   505→                    Priority
   506→                    Created
   507→

   508→

   509→

   510→                  {isLoading && tasks.length === 0 ? (
   511→

   512→
   513→                        Loading...
   514→
   515→

   516→                  ) : paginatedTasks.length === 0 ? (
   517→

   518→
   519→                        No tasks found
   520→
   521→

   522→                  ) : (
   523→                    paginatedTasks.map((task) => (
   524→
 handleSelectTask(task)}
   527→                        className={`border-t border-slate-700 hover:bg-slate-700/50 cursor-pointer ${
   528→                          selectedTask?.id === task.id ? 'bg-slate-700' : ''
   529→                        }`}
   530→                      >
   531→
   532→
{task.name}

   533→                          {task.description && (
   534→

   535→                              {task.description}
   536→

   537→                          )}
   538→
   539→
   540→
   547→                            {STATUS_LABELS[task.status] || task.status}
   548→
   549→
   550→
   551→
   557→                            {PRIORITY_LABELS[task.priority] || 'Unknown'}
   558→
   559→
   560→
   561→                          {new Date(task.created_at).toLocaleDateString()}
   562→
   563→

   564→                    ))
   565→                  )}
   566→

   567→

   568→

   569→
   570→            {/* Pagination Controls */}
   571→            {totalPages > 1 && (
   572→

   573→

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

   576→

   577→                  <button
   578→                    onClick={() => setCurrentPage(p => Math.max(1, p - 1))}
   579→                    disabled={currentPage === 1}
   580→                    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"
   581→                  >
   582→                    <ChevronLeft size={18} />
   583→                  </button>
   584→

   585→                    {Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
   586→                      <button
   587→                        key={page}
   588→                        onClick={() => setCurrentPage(page)}
   589→                        className={`w-8 h-8 rounded-lg text-sm ${
   590→                          page === currentPage
   591→                            ? 'bg-accent text-white'
   592→                            : 'bg-slate-800 border border-slate-700 text-slate-400 hover:text-white hover:bg-slate-700'
   593→                        }`}
   594→                      >
   595→                        {page}
   596→                      </button>
   597→                    ))}
   598→

   599→                  <button
   600→                    onClick={() => setCurrentPage(p => Math.min(totalPages, p + 1))}
   601→                    disabled={currentPage === totalPages}
   602→                    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"
   603→                  >
   604→                    <ChevronRight size={18} />
   605→                  </button>
   606→

   607→

   608→            )}
   609→

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

   622→

   623→
{column.title}

   624→
   625→                  {getTasksByStatus(column.id).length}
   626→
   627→

   628→

   629→
   630→            {/* Column Content */}
   631→

   632→              {isLoading && tasks.length === 0 ? (
   633→

   634→                  Loading...
   635→

   636→              ) : getTasksByStatus(column.id).length === 0 ? (
   637→

   638→                  No tasks
   639→

   640→              ) : (
   641→                getTasksByStatus(column.id).map((task) => (
   642→
 handleDragStart(task.id)}
   646→                    onClick={() => handleSelectTask(task)}
   647→                    className={`kanban-card bg-slate-900 rounded-lg p-4 border border-slate-700 cursor-pointer hover:border-slate-600 ${
   648→                      draggedTask === task.id ? 'opacity-50' : ''
   649→                    } ${selectedTask?.id === task.id ? 'ring-2 ring-accent' : ''}`}
   650→                  >
   651→

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

   654→
{task.name}

   655→                        {task.description && (
   656→

   657→                            {task.description}
   658→

   659→                        )}
   660→

   661→                          <span
   662→                            className={`badge ${
   663→                              column.id === 'backlog'
   664→                                ? 'badge-backlog'
   665→                                : column.id === 'in_progress'
   666→                                ? 'badge-in-progress'
   667→                                : column.id === 'qa'
   668→                                ? 'badge-qa'
   669→                                : column.id === 'done'
   670→                                ? 'badge-done'
   671→                                : 'badge-blocked'
   672→                            }`}
   673→                          >
   674→                            {column.title}
   675→
   676→
   682→                            {task.priority === 3 ? 'Critical' :
   683→                             task.priority === 2 ? 'High' :
   684→                             task.priority === 1 ? 'Medium' : 'Low'}
   685→
   686→

   687→

   688→

   689→

   690→                ))
   691→              )}
   692→

   693→

   694→          ))}
   695→

   696→        )}
   697→
   698→        {/* Task Details Panel */}
   699→        {selectedTask && (
   700→

   701→

   702→
Task Details

   703→

   704→                {!isEditing && (
   705→                  <>
   706→                    <button
   707→                      onClick={handleStartEdit}
   708→                      className="text-slate-400 hover:text-accent transition-colors"
   709→                      title="Edit Task"
   710→                    >
   711→                      <Pencil size={18} />
   712→                    </button>
   713→                    <AlertDialog.Root open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
   714→                      <AlertDialog.Trigger asChild>
   715→                        <button
   716→                          className="text-slate-400 hover:text-destructive transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
   717→                          title="Delete Task"
   718→                          disabled={isDeleting || (selectedTask ? isTaskDeleting(selectedTask.id) : false)}
   719→                        >
   720→                          <Trash2 size={18} />
   721→                        </button>
   722→                      </AlertDialog.Trigger>
   723→                      <AlertDialog.Portal>
   724→                        <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
   725→                        <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">
   726→                          <AlertDialog.Title className="text-xl font-semibold text-white">
   727→                            Delete Task
   728→                          </AlertDialog.Title>
   729→                          <AlertDialog.Description className="mt-3 text-slate-400">
   730→                            Are you sure you want to delete {selectedTask.name}?
   731→                            This action cannot be undone.
   732→                          </AlertDialog.Description>
   733→

   734→                            <AlertDialog.Cancel asChild>
   735→                              <button className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors">
   736→                                Cancel
   737→                              </button>
   738→                            </AlertDialog.Cancel>
   739→                            <AlertDialog.Action asChild>
   740→                              <button
   741→                                onClick={handleDeleteTask}
   742→                                disabled={isDeleting || (selectedTask ? isTaskDeleting(selectedTask.id) : false)}
   743→                                className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors disabled:opacity-50"
   744→                              >
   745→                                {isDeleting || (selectedTask && isTaskDeleting(selectedTask.id)) ? 'Deleting...' : 'Delete Task'}
   746→                              </button>
   747→                            </AlertDialog.Action>
   748→

   749→                        </AlertDialog.Content>
   750→                      </AlertDialog.Portal>
   751→                    </AlertDialog.Root>
   752→                  </>
   753→                )}
   754→                <button
   755→                  onClick={handleClosePanel}
   756→                  className="text-slate-400 hover:text-white transition-colors"
   757→                  title="Close"
   758→                >
   759→                  <X size={20} />
   760→                </button>
   761→

   762→

   763→

   764→              {isEditing ? (
   765→                /* Edit Form */
   766→

   767→

   768→                    Name *
   769→                    <input
   770→                      type="text"
   771→                      value={editName}
   772→                      onChange={(e) => setEditName(e.target.value)}
   773→                      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"
   774→                      placeholder="Task name"
   775→                    />
   776→

   777→

   778→                    Description
   779→                    <textarea
   780→                      value={editDescription}
   781→                      onChange={(e) => setEditDescription(e.target.value)}
   782→                      rows={3}
   783→                      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"
   784→                      placeholder="Task description"
   785→                    />
   786→

   787→

   788→                    Priority
   789→                    <select
   790→                      value={editPriority}
   791→                      onChange={(e) => setEditPriority(Number(e.target.value))}
   792→                      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"
   793→                    >
   794→                      <option value={0}>Low</option>
   795→                      <option value={1}>Medium</option>
   796→                      <option value={2}>High</option>
   797→                      <option value={3}>Critical</option>
   798→                    </select>
   799→

   800→

   801→                    <button
   802→                      onClick={handleCancelEdit}
   803→                      className="flex-1 px-3 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
   804→                    >
   805→                      Cancel
   806→                    </button>
   807→                    <button
   808→                      onClick={handleSaveEdit}
   809→                      disabled={isSaving || !editName.trim()}
   810→                      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"
   811→                    >
   812→                      {isSaving ? 'Saving...' : <><Check size={16} /> Save</>}
   813→                    </button>
   814→

   815→

   816→              ) : (
   817→                /* View Mode */
   818→                <>
   819→                  {/* Task Name */}
   820→

   821→                    Name
   822→
{selectedTask.name}

   823→

   824→
   825→                  {/* Description */}
   826→

   827→                    Description
   828→

   829→                      {selectedTask.description || No description}
   830→

   831→

   832→
   833→                  {/* Status */}
   834→

   835→                    Status
   836→
   843→                      {STATUS_LABELS[selectedTask.status] || selectedTask.status}
   844→
   845→

   846→
   847→                  {/* Priority */}
   848→

   849→                    Priority
   850→
   856→                      {PRIORITY_LABELS[selectedTask.priority] || 'Unknown'}
   857→
   858→

   859→
   860→                  {/* Agent Assignment */}
   861→

   862→
   863→                      <User size={14} />
   864→                      Agent Assignment
   865→
   866→

   867→                      {selectedTask.agent_type ? (
   868→                        {selectedTask.agent_type.replace('_', ' ')}
   869→                      ) : (
   870→                        Not assigned
   871→                      )}
   872→

   873→

   874→
   875→                  {/* Iteration Count */}
   876→

   877→
   878→                      <RefreshCw size={14} />
   879→                      Iteration Count
   880→
   881→
{selectedTask.iteration_count}

   882→

   883→
   884→                  {/* Flagged for Review */}
   885→

   886→
   887→                      <Flag size={14} />
   888→                      Flagged for Review
   889→
   890→

   891→                      {selectedTask.flagged_for_review ? 'Yes' : 'No'}
   892→

   893→

   894→
   895→                  {/* Time Estimates */}
   896→                  {(selectedTask.estimated_time || selectedTask.actual_time) && (
   897→

   898→
   899→                        <Clock size={14} />
   900→                        Time
   901→
   902→

   903→                        {selectedTask.estimated_time &&
Estimated: {selectedTask.estimated_time} min
}
   904→                        {selectedTask.actual_time &&
Actual: {selectedTask.actual_time} min
}
   905→

   906→

   907→                  )}
   908→
   909→                  {/* Created/Updated timestamps */}
   910→

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

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

   913→

   914→                </>
   915→              )}
   916→

   917→

   918→        )}
   919→
   920→        {/* Unsaved Changes Warning Dialog */}
   921→        <AlertDialog.Root open={showUnsavedDialog} onOpenChange={setShowUnsavedDialog}>
   922→          <AlertDialog.Portal>
   923→            <AlertDialog.Overlay className="fixed inset-0 bg-black/50 z-50" />
   924→            <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">
   925→              <AlertDialog.Title className="text-xl font-semibold text-white">
   926→                Unsaved Changes
   927→              </AlertDialog.Title>
   928→              <AlertDialog.Description className="mt-3 text-slate-400">
   929→                You have unsaved changes. Are you sure you want to discard them?
   930→              </AlertDialog.Description>
   931→

   932→                <AlertDialog.Cancel asChild>
   933→                  <button
   934→                    onClick={handleKeepEditing}
   935→                    className="px-4 py-2 text-sm text-slate-300 hover:bg-slate-700 rounded-lg transition-colors"
   936→                  >
   937→                    Keep Editing
   938→                  </button>
   939→                </AlertDialog.Cancel>
   940→                <AlertDialog.Action asChild>
   941→                  <button
   942→                    onClick={handleDiscardChanges}
   943→                    className="px-4 py-2 text-sm bg-destructive hover:bg-destructive/80 text-white rounded-lg transition-colors"
   944→                  >
   945→                    Discard Changes
   946→                  </button>
   947→                </AlertDialog.Action>
   948→

   949→            </AlertDialog.Content>
   950→          </AlertDialog.Portal>
   951→        </AlertDialog.Root>
   952→

   953→

   954→  )
   955→}
   956→

<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>

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)
  }

  // Reset all filters to defaults
  const handleResetFilters = () => {
    setPriorityFilter('all')
    setSortOrder('newest')
    setCurrentPage(1)
    const newParams = new URLSearchParams(searchParams)
    newParams.delete('priority')
    newParams.delete('sort')
    setSearchParams(newParams)
  }

  // Check if filters are active (non-default)
  const hasActiveFilters = priorityFilter !== 'all' || sortOrder !== 'newest'

  // 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
    // 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)
    }
  }

  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>

          {/* Reset Filters Button */}
          {hasActiveFilters && (
            <button
              onClick={handleResetFilters}
              className="flex items-center gap-1.5 px-3 py-1.5 text-sm text-slate-400 hover:text-white hover:bg-slate-700 rounded-lg transition-colors"
              title="Reset Filters"
            >
              <RefreshCw size={14} />
              Reset
            </button>
          )}

          {/* 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 disabled:opacity-50 disabled:cursor-not-allowed"
                          title="Delete Task"
                          disabled={isDeleting || (selectedTask ? isTaskDeleting(selectedTask.id) : false)}
                        >
                          <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 || (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>

                        </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>

  )
}


Excellent! Looking at KanbanBoard.tsx, I can see:
- Line 481: `disabled={isCreating || !newTaskName.trim()}` - ✅ Already uses `.trim()`
- Line 809: `disabled={isSaving || !editName.trim()}` - ✅ Already uses `.trim()`

The KanbanBoard already properly rejects whitespace-only input in the task forms.

Now I need to fix the ProjectWizard.tsx file where the button disabled state doesn't use `.trim()`:
- Line 518: `disabled={step === 1 && !formData.name}` - ❌ Doesn't check `.trim()`
- Line 527: `disabled={isLoading || !formData.name}` - ❌ Doesn't check `.trim()`

Let me fix these:


Edit

        {step < totalSteps ? (
          <button
            onClick={handleNext}
            disabled={step === 1 && !formData.name}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Next
            <ArrowRight size={18} />
          </button>
        ) : (
          <button
            onClick={handleSubmit}
            disabled={isLoading || !formData.name}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >

        {step < totalSteps ? (
          <button
            onClick={handleNext}
            disabled={step === 1 && !formData.name.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Next
            <ArrowRight size={18} />
          </button>
        ) : (
          <button
            onClick={handleSubmit}
            disabled={isLoading || !formData.name.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >


The file C:\Users\MikeSwanson\AutoBuilder\My-Auto-Builder\frontend\src\pages\ProjectWizard.tsx has been updated. Here's the result of running `cat -n` on a snippet of the edited file:
   511→          <ArrowLeft size={18} />
   512→          {step === 1 ? 'Cancel' : 'Back'}
   513→        </button>
   514→
   515→        {step < totalSteps ? (
   516→          <button
   517→            onClick={handleNext}
   518→            disabled={step === 1 && !formData.name.trim()}
   519→            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
   520→          >
   521→            Next
   522→            <ArrowRight size={18} />
   523→          </button>
   524→        ) : (
   525→          <button
   526→            onClick={handleSubmit}
   527→            disabled={isLoading || !formData.name.trim()}
   528→            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
   529→          >
   530→            {isLoading ? (
   531→              <>
   532→                <Loader2 size={18} className="animate-spin" />
   533→                Creating...

        {step < totalSteps ? (
          <button
            onClick={handleNext}
            disabled={step === 1 && !formData.name.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Next
            <ArrowRight size={18} />
          </button>
        ) : (
          <button
            onClick={handleSubmit}
            disabled={isLoading || !formData.name.trim()}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >

import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import { useProjectStore } from '../stores/projectStore'
import { ArrowLeft, ArrowRight, Check, Loader2, Plus, X } from 'lucide-react'

interface TechStack {
  frontend: string[]
  backend: string[]
  database: string[]
  other: string[]
}

interface DesignPreferences {
  theme: 'light' | 'dark' | 'system'
  primaryColor: string
  style: 'minimal' | 'modern' | 'classic'
  designMode: 'mvp' | 'finished'
}

export default function ProjectWizard() {
  const navigate = useNavigate()
  const { createProject, isLoading } = useProjectStore()
  const [step, setStep] = useState(1)
  const [formData, setFormData] = useState({
    name: '',
    description: '',
    complexity: 'medium',
    path: '',
  })
  const [techStack, setTechStack] = useState<TechStack>({
    frontend: [],
    backend: [],
    database: [],
    other: [],
  })
  const [features, setFeatures] = useState<string[]>([])
  const [newFeature, setNewFeature] = useState('')
  const [designPreferences, setDesignPreferences] = useState<DesignPreferences>({
    theme: 'dark',
    primaryColor: '#0d9488',
    style: 'modern',
    designMode: 'mvp',
  })
  const [errors, setErrors] = useState<{ name?: string }>({})
  const [touched, setTouched] = useState<{ name?: boolean }>({})

  const totalSteps = 5

  const validateName = (name: string): string | undefined => {
    if (!name.trim()) {
      return 'Project name is required'
    }
    if (name.trim().length < 2) {
      return 'Project name must be at least 2 characters'
    }
    if (name.trim().length > 100) {
      return 'Project name must be less than 100 characters'
    }
    return undefined
  }

  const handleNext = () => {
    if (step === 1) {
      const nameError = validateName(formData.name)
      setTouched({ ...touched, name: true })
      setErrors({ ...errors, name: nameError })
      if (nameError) return
    }
    if (step < totalSteps) {
      setStep(step + 1)
    }
  }

  const handleBack = () => {
    if (step > 1) {
      setStep(step - 1)
    }
  }

  const handleSubmit = async () => {
    try {
      await createProject({
        name: formData.name,
        description: formData.description,
        design_mode: designPreferences.designMode,
      })
      navigate('/')
    } catch (error) {
      console.error('Failed to create project:', error)
    }
  }

  return (

      {/* Progress */}

            Step {step} of {totalSteps}

            {Math.round((step / totalSteps) * 100)}% complete

          <div
            className="h-full bg-accent transition-all duration-300"
            style={{ width: `${(step / totalSteps) * 100}%` }}
          />

      {/* Step Content */}

        {step === 1 && (

Project Basics

                  Project Name *

                <input
                  type="text"
                  value={formData.name}
                  onChange={(e) => {
                    const newName = e.target.value
                    setFormData({ ...formData, name: newName })
                    if (touched.name) {
                      setErrors({ ...errors, name: validateName(newName) })
                    }
                  }}
                  onBlur={() => {
                    setTouched({ ...touched, name: true })
                    setErrors({ ...errors, name: validateName(formData.name) })
                  }}
                  placeholder="My Awesome Project"
                  className={`w-full px-4 py-2 bg-slate-700 border rounded-lg focus:outline-none focus:ring-2 ${
                    touched.name && errors.name
                      ? 'border-red-500 focus:ring-red-500'
                      : 'border-slate-600 focus:ring-accent'
                  }`}
                />
                {touched.name && errors.name && (

{errors.name}

                )}

                  Description

                <textarea
                  value={formData.description}
                  onChange={(e) =>
                    setFormData({ ...formData, description: e.target.value })
                  }
                  placeholder="A brief description of your project..."
                  rows={3}
                  className="w-full px-4 py-2 bg-slate-700 border border-slate-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent"
                />

        )}

        {step === 2 && (

Technology Stack

              {/* Frontend Technologies */}

                Frontend

                  {['React', 'Vue', 'Angular', 'Svelte', 'Next.js', 'HTML/CSS'].map((tech) => (
                    <button
                      key={tech}
                      onClick={() => {
                        const current = techStack.frontend
                        setTechStack({
                          ...techStack,
                          frontend: current.includes(tech)
                            ? current.filter((t) => t !== tech)
                            : [...current, tech],
                        })
                      }}
                      className={`px-3 py-1.5 rounded-lg border text-sm transition-colors ${
                        techStack.frontend.includes(tech)
                          ? 'border-accent bg-accent/20 text-accent'
                          : 'border-slate-600 hover:border-slate-500'
                      }`}
                    >
                      {tech}
                    </button>
                  ))}

              {/* Backend Technologies */}

                Backend

                  {['Python', 'Node.js', 'Go', 'Rust', 'Java', 'Ruby', 'PHP'].map((tech) => (
                    <button
                      key={tech}
                      onClick={() => {
                        const current = techStack.backend
                        setTechStack({
                          ...techStack,
                          backend: current.includes(tech)
                            ? current.filter((t) => t !== tech)
                            : [...current, tech],
                        })
                      }}
                      className={`px-3 py-1.5 rounded-lg border text-sm transition-colors ${
                        techStack.backend.includes(tech)
                          ? 'border-accent bg-accent/20 text-accent'
                          : 'border-slate-600 hover:border-slate-500'
                      }`}
                    >
                      {tech}
                    </button>
                  ))}

              {/* Database */}

                Database

                  {['PostgreSQL', 'MySQL', 'SQLite', 'MongoDB', 'Redis', 'Firebase'].map((tech) => (
                    <button
                      key={tech}
                      onClick={() => {
                        const current = techStack.database
                        setTechStack({
                          ...techStack,
                          database: current.includes(tech)
                            ? current.filter((t) => t !== tech)
                            : [...current, tech],
                        })
                      }}
                      className={`px-3 py-1.5 rounded-lg border text-sm transition-colors ${
                        techStack.database.includes(tech)
                          ? 'border-accent bg-accent/20 text-accent'
                          : 'border-slate-600 hover:border-slate-500'
                      }`}
                    >
                      {tech}
                    </button>
                  ))}

        )}

        {step === 3 && (

Features

              Add the main features you want your project to have.

              {/* Add feature input */}

                <input
                  type="text"
                  value={newFeature}
                  onChange={(e) => setNewFeature(e.target.value)}
                  onKeyDown={(e) => {
                    if (e.key === 'Enter' && newFeature.trim()) {
                      setFeatures([...features, newFeature.trim()])
                      setNewFeature('')
                    }
                  }}
                  placeholder="Enter a feature..."
                  className="flex-1 px-4 py-2 bg-slate-700 border border-slate-600 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent"
                />
                <button
                  onClick={() => {
                    if (newFeature.trim()) {
                      setFeatures([...features, newFeature.trim()])
                      setNewFeature('')
                    }
                  }}
                  disabled={!newFeature.trim()}
                  className="btn-accent disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  <Plus size={18} />
                </button>

              {/* Feature list */}

                {features.length === 0 ? (

No features added yet

                ) : (
                  features.map((feature, index) => (

                      {feature}
                      <button
                        onClick={() => setFeatures(features.filter((_, i) => i !== index))}
                        className="text-slate-400 hover:text-destructive transition-colors"
                      >
                        <X size={16} />
                      </button>

                  ))
                )}

        )}

        {step === 4 && (

Design Preferences

              {/* Design Mode - MVP vs Finished */}

                Design Mode

                  Choose how strictly design requirements should be applied.

                  <button
                    onClick={() => setDesignPreferences({ ...designPreferences, designMode: 'mvp' })}
                    className={`w-full p-4 rounded-lg border text-left transition-colors ${
                      designPreferences.designMode === 'mvp'
                        ? 'border-accent bg-accent/10'
                        : 'border-slate-600 hover:border-slate-500'
                    }`}
                  >

MVP Mode

                      {designPreferences.designMode === 'mvp' && (
                        Selected
                      )}

                      Functional drafts are acceptable. Focus on getting features working first,
                      with polished design coming later. Best for rapid prototyping and early development.

                  </button>
                  <button
                    onClick={() => setDesignPreferences({ ...designPreferences, designMode: 'finished' })}
                    className={`w-full p-4 rounded-lg border text-left transition-colors ${
                      designPreferences.designMode === 'finished'
                        ? 'border-accent bg-accent/10'
                        : 'border-slate-600 hover:border-slate-500'
                    }`}
                  >

Finished Mode

                      {designPreferences.designMode === 'finished' && (
                        Selected
                      )}

                      Stricter design requirements apply. All frontend work must meet polish standards
                      with proper typography, color, motion, and spatial composition. Best for production-ready builds.

                  </button>

              {/* Theme */}

                Theme

                  {(['light', 'dark', 'system'] as const).map((theme) => (
                    <button
                      key={theme}
                      onClick={() => setDesignPreferences({ ...designPreferences, theme })}
                      className={`flex-1 p-3 rounded-lg border text-center capitalize transition-colors ${
                        designPreferences.theme === theme
                          ? 'border-accent bg-accent/10'
                          : 'border-slate-600 hover:border-slate-500'
                      }`}
                    >
                      {theme}
                    </button>
                  ))}

              {/* Style */}

                UI Style

                  {(['minimal', 'modern', 'classic'] as const).map((style) => (
                    <button
                      key={style}
                      onClick={() => setDesignPreferences({ ...designPreferences, style })}
                      className={`w-full p-3 rounded-lg border text-left transition-colors ${
                        designPreferences.style === style
                          ? 'border-accent bg-accent/10'
                          : 'border-slate-600 hover:border-slate-500'
                      }`}
                    >

{style}

                        {style === 'minimal' && 'Clean and simple design'}
                        {style === 'modern' && 'Contemporary with subtle effects'}
                        {style === 'classic' && 'Traditional and familiar layout'}

                    </button>
                  ))}

              {/* Primary Color */}

                Primary Color

                  {['#0d9488', '#3b82f6', '#8b5cf6', '#ef4444', '#f59e0b'].map((color) => (
                    <button
                      key={color}
                      onClick={() => setDesignPreferences({ ...designPreferences, primaryColor: color })}
                      className={`w-10 h-10 rounded-lg border-2 transition-transform ${
                        designPreferences.primaryColor === color
                          ? 'border-white scale-110'
                          : 'border-transparent hover:scale-105'
                      }`}
                      style={{ backgroundColor: color }}
                    />
                  ))}

        )}

        {step === 5 && (

Review & Create

              {/* Project Basics */}

Project Name

{formData.name || 'Not set'}

Description

                  {formData.description || 'No description'}

              {/* Technology Stack */}

Technology Stack

                  {techStack.frontend.length > 0 && (

Frontend: {techStack.frontend.join(', ')}

                  )}
                  {techStack.backend.length > 0 && (

Backend: {techStack.backend.join(', ')}

                  )}
                  {techStack.database.length > 0 && (

Database: {techStack.database.join(', ')}

                  )}
                  {techStack.frontend.length === 0 && techStack.backend.length === 0 && techStack.database.length === 0 && (

No technologies selected

                  )}

              {/* Features */}

Features

                {features.length > 0 ? (

                    {features.map((feature, i) => (

{feature}

                    ))}

                ) : (

No features added

                )}

              {/* Design Preferences */}

Design Preferences

                    Design Mode:{' '}

                      {designPreferences.designMode === 'mvp' ? 'MVP (Functional Drafts)' : 'Finished (Polished)'}

Theme: {designPreferences.theme}

Style: {designPreferences.style}

                    Primary Color:

        )}

      {/* Navigation */}

        <button
          onClick={step === 1 ? () => navigate('/') : handleBack}
          className="btn-secondary flex items-center gap-2"
        >
          <ArrowLeft size={18} />
          {step === 1 ? 'Cancel' : 'Back'}
        </button>

        {step < totalSteps ? (
          <button
            onClick={handleNext}
            disabled={step === 1 && !formData.name}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            Next
            <ArrowRight size={18} />
          </button>
        ) : (
          <button
            onClick={handleSubmit}
            disabled={isLoading || !formData.name}
            className="btn-accent flex items-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            {isLoading ? (
              <>
                <Loader2 size={18} className="animate-spin" />
                Creating...
              </>
            ) : (
              <>
                <Check size={18} />
                Create Project
              </>
            )}
          </button>
        )}

  )
}

-            disabled={step === 1 && !formData.name}

+            disabled={step === 1 && !formData.name.trim()}

-            disabled={isLoading || !formData.name}

+            disabled={isLoading || !formData.name.trim()}


Now let me also check the MemoryManager for form validation: