import { useState, useEffect, useCallback } from 'react';
import {
  DndContext, DragOverlay, useDroppable, useDraggable,
  PointerSensor, TouchSensor, useSensor, useSensors, closestCenter
} from '@dnd-kit/core';
import {
  Plus, User, Calendar, Zap, ArrowRight, FolderKanban,
  CheckSquare, Bell, Target, AlertTriangle, MoreHorizontal, GripVertical
} from 'lucide-react';
import { Link, useNavigate } from 'react-router-dom';
import toast from 'react-hot-toast';
import api from '../api';
import TaskModal from './TaskModal';
import ConfirmDialog from './ConfirmDialog';
import { getCategoryClass, getPriorityClass, CATEGORIES, formatDate, isOverdue } from '../utils';

// ── Column config ────────────────────────────────────────────────────────────
const COLUMNS = [
  { id: 'focus',      title: "Today's Focus", color: 'text-primary',    bg: 'bg-primary/10',  border: 'border-l-primary'  },
  { id: 'inprogress', title: 'In Progress',   color: 'text-blue-600',   bg: 'bg-blue-50 dark:bg-blue-900/20',   border: 'border-l-blue-400'   },
  { id: 'followups',  title: 'Follow-ups',    color: 'text-amber-600',  bg: 'bg-amber-50 dark:bg-amber-900/20', border: 'border-l-amber-400'  },
  { id: 'open',       title: 'Open',          color: 'text-gray-500',   bg: 'bg-gray-100 dark:bg-gray-800',     border: 'border-l-gray-300'   },
];

const PRIORITY_BORDER = { Urgent:'border-l-red-500', High:'border-l-amber-400', Medium:'border-l-blue-400', Low:'border-l-green-400' };

function getColumnId(task) {
  if (task.status === 'Done') return null;
  if (task.is_today_focus)    return 'focus';
  if (task.status === 'In Progress') return 'inprogress';
  if (task.is_follow_up)      return 'followups';
  return 'open';
}

function columnUpdates(col, task) {
  const base = { ...task };
  if (col === 'focus')      return { ...base, is_today_focus: 1 };
  if (col === 'inprogress') return { ...base, status: 'In Progress', is_today_focus: 0 };
  if (col === 'followups')  return { ...base, is_follow_up: 1,  is_today_focus: 0 };
  if (col === 'open')       return { ...base, is_today_focus: 0, status: 'Open' };
  return base;
}

// ── Draggable card ───────────────────────────────────────────────────────────
function DraggableCard({ task, onEdit, onDelete, onMarkDone }) {
  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id: task.id });
  const overdue = isOverdue(task.due_date);

  return (

          {/* Drag handle */}
          <button {...listeners} {...attributes}
            className="shrink-0 mt-0.5 text-gray-300 hover:text-gray-500 cursor-grab active:cursor-grabbing touch-none">
            <GripVertical size={14} />
          </button>

{task.title}

              <button onClick={() => onEdit(task)}
                className="shrink-0 opacity-0 group-hover:opacity-100 p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-400 transition-all">
                <MoreHorizontal size={13} />
              </button>

            {task.notes &&
{task.notes}
}

              <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
                {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}

              <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
              {task.is_follow_up === 1 && Follow-up}

                {task.assignee ? (

                    {task.assignee[0].toUpperCase()}

                ) :
<User size={9} className="text-gray-400" />
}
                {task.assignee && {task.assignee}}

                {task.due_date && (
                  <span className={`flex items-center gap-0.5 text-[10px] ${overdue ? 'text-red-500 font-semibold' : 'text-gray-400'}`}>
                    {overdue && <AlertTriangle size={9} />}{formatDate(task.due_date)}

                )}
                <button onClick={() => onMarkDone(task)}
                  className="opacity-0 group-hover:opacity-100 text-[10px] px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 rounded-full hover:bg-green-200 transition-all font-medium">
                  Done
                </button>

  );
}

// ── Drag overlay card (ghost while dragging) ─────────────────────────────────
function OverlayCard({ task }) {
  return (

{task.title}

        <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
        <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
          {CATEGORIES[task.category]?.label?.split(' ')[0]}

  );
}

// ── Droppable column ─────────────────────────────────────────────────────────
function DroppableColumn({ col, tasks, stats, onAddTask, onEdit, onDelete, onMarkDone }) {
  const { setNodeRef, isOver } = useDroppable({ id: col.id });

  return (

      {/* Column header */}

{col.title}

          <span className={`text-xs font-bold px-2 py-0.5 rounded-full ${col.bg} ${col.color}`}>{tasks.length}

        <button onClick={onAddTask}
          className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all shadow-sm">
          <Plus size={12} />
        </button>

      {/* Cards */}

        {tasks.length === 0 ? (

Drop here

        ) : (
          tasks.map(task => (
            <DraggableCard key={task.id} task={task} onEdit={onEdit} onDelete={onDelete} onMarkDone={onMarkDone} />
          ))
        )}

  );
}

// ── Main Dashboard ───────────────────────────────────────────────────────────
export default function Today() {
  const [allTasks, setAllTasks]     = useState([]);
  const [stats, setStats]           = useState(null);
  const [projects, setProjects]     = useState([]);
  const [loading, setLoading]       = useState(true);
  const [editTask, setEditTask]     = useState(null);
  const [deleteTask, setDeleteTask] = useState(null);
  const [showNew, setShowNew]       = useState(false);
  const [newDefaults, setNewDefaults] = useState({});
  const [activeTask, setActiveTask] = useState(null);
  const [activeTab, setActiveTab]   = useState('dashboard');
  const navigate = useNavigate();

  const today = new Date();
  const dateLabel = today.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });

  const load = useCallback(async () => {
    try {
      const [tasks, st, pr] = await Promise.all([api.get('/tasks'), api.get('/tasks/stats'), api.get('/projects')]);
      setAllTasks(tasks); setStats(st); setProjects(pr);
    } finally { setLoading(false); }
  }, []);

  useEffect(() => { load(); }, [load]);

  // Bucket tasks into columns
  const columns = COLUMNS.map(col => ({
    ...col,
    tasks: allTasks.filter(t => getColumnId(t) === col.id),
  }));

  // DnD sensors — support mouse, touch (mobile), delay to prevent accidental drags
  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
    useSensor(TouchSensor,   { activationConstraint: { delay: 180, tolerance: 6 } })
  );

  const onDragStart = ({ active }) => {
    setActiveTask(allTasks.find(t => t.id === active.id) || null);
  };

  const onDragEnd = async ({ active, over }) => {
    setActiveTask(null);
    if (!over) return;
    const task = allTasks.find(t => t.id === active.id);
    if (!task) return;
    const targetCol = COLUMNS.find(c => c.id === over.id);
    if (!targetCol || getColumnId(task) === targetCol.id) return;

    // Optimistic update
    const updated = columnUpdates(targetCol.id, task);
    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, ...updated } : t));
    try {
      await api.put(`/tasks/${task.id}`, updated);
      toast.success(`Moved to "${targetCol.title}"`);
    } catch (e) {
      toast.error('Failed to move task'); load();
    }
  };

  const markDone = async (task) => {
    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'Done' } : t));
    await api.patch(`/tasks/${task.id}/status`, { status: 'Done' });
    toast.success('Marked as done');
  };

  const openNew = (defaults = {}) => { setNewDefaults(defaults); setShowNew(true); };

  const handleSave = async (form) => {
    try {
      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
      else { await api.post('/tasks', { ...form, ...newDefaults }); toast.success('Task added'); }
      setEditTask(null); setShowNew(false); load();
    } catch (e) { toast.error(e.message); }
  };

  const handleDelete = async () => {
    await api.delete(`/tasks/${deleteTask.id}`);
    toast.success('Deleted'); setDeleteTask(null); load();
  };

  const TABS = [
    { id: 'dashboard', label: 'Dashboard' },
    { id: 'all',       label: 'All Tasks'      },
    { id: 'projects',  label: 'Projects'       },
  ];

  return (

      {/* Hero banner */}

              <Zap size={17} className="text-violet-600" />

DEWA AI Workspace

{dateLabel}

            {[
              { label: 'Projects',     value: stats?.activeProjects ?? '—', Icon: FolderKanban },
              { label: 'Open Tasks',   value: stats?.openTasks      ?? '—', Icon: CheckSquare  },
              { label: 'Follow-ups',   value: stats?.openFollowUps  ?? '—', Icon: Bell         },
              { label: "Today's Focus",value: stats?.todayFocus     ?? '—', Icon: Target       },
            ].map(({ label, value, Icon }) => (

{value}

                  <Icon size={9} />{label}

            ))}

      {/* Tabs */}

        {TABS.map(t => (
          <button key={t.id} onClick={() => setActiveTab(t.id)}
            className={`px-3.5 py-1.5 rounded-xl text-sm font-medium transition-all duration-150 ${
              activeTab === t.id
                ? 'bg-primary text-white shadow-sm'
                : 'text-gray-500 dark:text-gray-400 hover:bg-white dark:hover:bg-gray-800 hover:text-gray-800 dark:hover:text-white'
            }`}>
            {t.label}
          </button>
        ))}

        <button onClick={() => openNew({ is_today_focus: 1 })} className="btn-primary flex items-center gap-1 py-1.5 text-xs">
          <Plus size={12} /> New Task
        </button>

      {/* ── Kanban Board (drag & drop) ─────────────────────────────────── */}
      {loading ? (

          {[1,2,3,4].map(i =>
)}

      ) : (
        <>
          {activeTab === 'dashboard' && (
            <DndContext sensors={sensors} collisionDetection={closestCenter} onDragStart={onDragStart} onDragEnd={onDragEnd}>
              {/* Horizontal scrollable kanban — snaps on mobile */}

                {columns.map(col => (
                  <DroppableColumn
                    key={col.id} col={col} tasks={col.tasks}
                    onAddTask={() => openNew(
                      col.id === 'focus'      ? { is_today_focus: 1 } :
                      col.id === 'inprogress' ? { status: 'In Progress' } :
                      col.id === 'followups'  ? { is_follow_up: 1 } : {}
                    )}
                    onEdit={setEditTask}
                    onDelete={setDeleteTask}
                    onMarkDone={markDone}
                  />
                ))}

              {/* Drag overlay */}
              <DragOverlay dropAnimation={{ duration: 180, easing: 'cubic-bezier(0.18,0.67,0.6,1.22)' }}>
                {activeTask && <OverlayCard task={activeTask} />}
              </DragOverlay>
            </DndContext>
          )}

          {/* ALL TASKS — horizontal grid */}
          {activeTab === 'all' && (

                {allTasks.filter(t => t.status !== 'Done').map(task => (

 setEditTask(task)}>

{task.title}

                      <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
                      <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
                        {CATEGORIES[task.category]?.label?.split(' ')[0]}

                    {task.assignee && (

                          {task.assignee[0].toUpperCase()}

                        {task.assignee}

                    )}

                ))}

          )}

          {/* PROJECTS — horizontal grid */}
          {activeTab === 'projects' && (

                {projects.filter(p => p.status !== 'Done').map(p => (
                  <button key={p.id} onClick={() => navigate(`/projects/${p.id}`)}
                    className="card-hover text-left p-4 group">

                      <span className={`badge text-[10px] ${getCategoryClass(p.category)}`}>
                        {CATEGORIES[p.category]?.label?.split(' ')[0] || p.category}

                      <ArrowRight size={12} className="text-gray-300 group-hover:text-primary transition-colors" />

{p.name}

                      <span className={`font-semibold ${p.priority === 'Urgent' ? 'text-red-500' : p.priority === 'High' ? 'text-amber-500' : ''}`}>{p.priority}
                      {p.open_task_count || 0} tasks

                  </button>
                ))}

          )}
        </>
      )}

      {/* Modals */}
      {(showNew || editTask) && (
        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />
      )}
      {deleteTask && (
        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
      )}

  );
}

import { useState, useEffect, useCallback } from 'react';

-import { Plus, MoreHorizontal, User, Calendar, Zap, ArrowRight, FolderKanban, CheckSquare, Bell, Target, AlertTriangle } from 'lucide-react';

+  DndContext, DragOverlay, useDroppable, useDraggable,

+  PointerSensor, TouchSensor, useSensor, useSensors, closestCenter

+  Plus, User, Calendar, Zap, ArrowRight, FolderKanban,

+  CheckSquare, Bell, Target, AlertTriangle, MoreHorizontal, GripVertical

import { Link, useNavigate } from 'react-router-dom';

import ConfirmDialog from './ConfirmDialog';

-// ─── Kanban Task Card ───────────────────────────────────────────────────────

-function KanbanCard({ task, onEdit, onDelete, onToggleFocus, onMarkDone }) {

-  const overdue = isOverdue(task.due_date) && task.status !== 'Done';

-  }[task.priority] || 'border-l-gray-200';

+// ── Column config ────────────────────────────────────────────────────────────

+  { id: 'focus',      title: "Today's Focus", color: 'text-primary',    bg: 'bg-primary/10',  border: 'border-l-primary'  },

+  { id: 'inprogress', title: 'In Progress',   color: 'text-blue-600',   bg: 'bg-blue-50 dark:bg-blue-900/20',   border: 'border-l-blue-400'   },

+  { id: 'followups',  title: 'Follow-ups',    color: 'text-amber-600',  bg: 'bg-amber-50 dark:bg-amber-900/20', border: 'border-l-amber-400'  },

+  { id: 'open',       title: 'Open',          color: 'text-gray-500',   bg: 'bg-gray-100 dark:bg-gray-800',     border: 'border-l-gray-300'   },

+const PRIORITY_BORDER = { Urgent:'border-l-red-500', High:'border-l-amber-400', Medium:'border-l-blue-400', Low:'border-l-green-400' };

+  if (task.status === 'Done') return null;

+  if (task.is_today_focus)    return 'focus';

+  if (task.status === 'In Progress') return 'inprogress';

+  if (task.is_follow_up)      return 'followups';

+  if (col === 'focus')      return { ...base, is_today_focus: 1 };

+  if (col === 'inprogress') return { ...base, status: 'In Progress', is_today_focus: 0 };

+  if (col === 'followups')  return { ...base, is_follow_up: 1,  is_today_focus: 0 };

+  if (col === 'open')       return { ...base, is_today_focus: 0, status: 'Open' };

+// ── Draggable card ───────────────────────────────────────────────────────────

+function DraggableCard({ task, onEdit, onDelete, onMarkDone }) {

+  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id: task.id });

+  const overdue = isOverdue(task.due_date);

-    <div className={`kanban-card border-l-4 ${priorityBorder} group`}>

-      <div className="flex items-start justify-between gap-2 mb-2">

-          className="shrink-0 opacity-0 group-hover:opacity-100 p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-400 transition-all"

+      style={{ opacity: isDragging ? 0.35 : 1, touchAction: 'none' }}

+      className={`bg-white dark:bg-gray-900 rounded-xl border border-gray-100 dark:border-gray-800

+        border-l-4 ${PRIORITY_BORDER[task.priority] || 'border-l-gray-200'}

+        shadow-card transition-all duration-150 group

+        ${isDragging ? '' : 'hover:shadow-hover hover:-translate-y-0.5'}`}

+        <div className="flex items-start gap-2">

+          <button {...listeners} {...attributes}

+            className="shrink-0 mt-0.5 text-gray-300 hover:text-gray-500 cursor-grab active:cursor-grabbing touch-none">

+          <div className="flex-1 min-w-0">

+            <div className="flex items-start justify-between gap-1.5">

+              <button onClick={() => onEdit(task)}

+                className="shrink-0 opacity-0 group-hover:opacity-100 p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-400 transition-all">

+                <MoreHorizontal size={13} />

-      <div className="flex flex-wrap gap-1.5 mb-3">

-        <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>

-          {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}

-        <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}

+            {task.notes &&
{task.notes}
}

-      <div className="flex items-center justify-between pt-2 border-t border-gray-100 dark:border-gray-800">

-        <div className="flex items-center gap-2">

-            <div className="w-6 h-6 rounded-full bg-gradient-to-br from-primary to-brand-pink flex items-center justify-center text-white text-[9px] font-bold">

-              {task.assignee[0]?.toUpperCase()}

+            <div className="flex flex-wrap gap-1 mt-2">

+              <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>

+                {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}

+              <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}

+              {task.is_follow_up === 1 && Follow-up}

-            <div className="w-6 h-6 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center">

-              <User size={10} className="text-gray-400" />

+            <div className="flex items-center justify-between mt-2 pt-2 border-t border-gray-100 dark:border-gray-800">

+              <div className="flex items-center gap-1.5">

+                  <div className="w-5 h-5 rounded-full bg-gradient-to-br from-primary to-brand-pink flex items-center justify-center text-white text-[9px] font-bold shrink-0">

+                    {task.assignee[0].toUpperCase()}

+                ) :
<User size={9} className="text-gray-400" />
}

+                {task.assignee && {task.assignee}}

+                  <span className={`flex items-center gap-0.5 text-[10px] ${overdue ? 'text-red-500 font-semibold' : 'text-gray-400'}`}>

+                    {overdue && <AlertTriangle size={9} />}{formatDate(task.due_date)}

+                <button onClick={() => onMarkDone(task)}

+                  className="opacity-0 group-hover:opacity-100 text-[10px] px-2 py-0.5 bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-400 rounded-full hover:bg-green-200 transition-all font-medium">

-          {task.assignee && {task.assignee}}

-        <div className="flex items-center gap-2">

-            <span className={`flex items-center gap-1 text-[10px] ${overdue ? 'text-red-500 font-semibold' : 'text-gray-400'}`}>

-              {overdue && <AlertTriangle size={10} className="text-red-500" />}{formatDate(task.due_date)}

-              onClick={() => onMarkDone(task)}

-              className="opacity-0 group-hover:opacity-100 text-[10px] px-2 py-0.5 bg-green-100 text-green-700 rounded-full hover:bg-green-200 transition-all font-medium"

+// ── Drag overlay card (ghost while dragging) ─────────────────────────────────

+    <div className={`bg-white dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-700 border-l-4

+      ${PRIORITY_BORDER[task.priority]} shadow-hover p-3 w-[260px] rotate-2 opacity-95`}>

+      <div className="flex gap-1 mt-1.5">

+        <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>

+          {CATEGORIES[task.category]?.label?.split(' ')[0]}

-// ─── Kanban Column ──────────────────────────────────────────────────────────

-function KanbanColumn({ title, count, tasks, color, onAddTask, onEdit, onDelete, onToggleFocus, onMarkDone, emptyText }) {

+// ── Droppable column ─────────────────────────────────────────────────────────

+function DroppableColumn({ col, tasks, stats, onAddTask, onEdit, onDelete, onMarkDone }) {

+  const { setNodeRef, isOver } = useDroppable({ id: col.id });

-    <div className="kanban-col shrink-0">

+    <div className={`flex flex-col rounded-2xl transition-all duration-200 min-w-[260px] w-[260px] sm:w-[270px]

+      ${isOver ? 'ring-2 ring-primary/50 bg-primary/5 scale-[1.01]' : 'bg-[#F7F7FB] dark:bg-gray-800/40'}`}

+      style={{ scrollSnapAlign: 'start', maxHeight: 'calc(100vh - 270px)' }}

-      <div className="flex items-center justify-between mb-3 px-1">

+      <div className="flex items-center justify-between px-3 pt-3 pb-2 shrink-0">

<div className="flex items-center gap-2">

-          <span className={`text-xs font-bold px-2 py-0.5 rounded-full ${color}`}>{count}

+          <span className={`text-xs font-bold px-2 py-0.5 rounded-full ${col.bg} ${col.color}`}>{tasks.length}

-        <button onClick={onAddTask} className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all shadow-sm">

+          className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all shadow-sm">

+      <div ref={setNodeRef} className="flex-1 overflow-y-auto px-3 pb-3 space-y-2.5 min-h-[60px]">

-          <div className="text-center py-8">

+          <div className={`border-2 border-dashed rounded-xl flex items-center justify-center h-20 transition-colors

+            ${isOver ? 'border-primary/40 bg-primary/5' : 'border-gray-200 dark:border-gray-700'}`}>

-              onToggleFocus={onToggleFocus}

+            <DraggableCard key={task.id} task={task} onEdit={onEdit} onDelete={onDelete} onMarkDone={onMarkDone} />

-// ─── Main Component ─────────────────────────────────────────────────────────

+// ── Main Dashboard ───────────────────────────────────────────────────────────

-  const [allTasks, setAllTasks] = useState([]);

-  const [stats, setStats] = useState(null);

-  const [projects, setProjects] = useState([]);

-  const [loading, setLoading] = useState(true);

-  const [editTask, setEditTask] = useState(null);

+  const [allTasks, setAllTasks]     = useState([]);

+  const [stats, setStats]           = useState(null);

+  const [projects, setProjects]     = useState([]);

+  const [loading, setLoading]       = useState(true);

+  const [editTask, setEditTask]     = useState(null);

const [deleteTask, setDeleteTask] = useState(null);

-  const [showNewTask, setShowNewTask] = useState(false);

-  const [newTaskDefaults, setNewTaskDefaults] = useState({});

-  const [activeTab, setActiveTab] = useState('dashboard');

+  const [showNew, setShowNew]       = useState(false);

+  const [newDefaults, setNewDefaults] = useState({});

+  const [activeTask, setActiveTask] = useState(null);

+  const [activeTab, setActiveTab]   = useState('dashboard');

-      const [tasks, st, pr] = await Promise.all([

+      const [tasks, st, pr] = await Promise.all([api.get('/tasks'), api.get('/tasks/stats'), api.get('/projects')]);

+      setAllTasks(tasks); setStats(st); setProjects(pr);

-  // ── Kanban buckets ──────────────────────────────────────────────────────

-  const focusTasks     = allTasks.filter(t => t.is_today_focus && t.status !== 'Done');

-  const inProgressTasks = allTasks.filter(t => !t.is_today_focus && t.status === 'In Progress');

-  const followUpTasks  = allTasks.filter(t => t.is_follow_up && t.status !== 'Done' && !t.is_today_focus);

+  const columns = COLUMNS.map(col => ({

+    tasks: allTasks.filter(t => getColumnId(t) === col.id),

-  // ── Handlers ────────────────────────────────────────────────────────────

-  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };

-  const markDone    = async (task) => {

+  // DnD sensors — support mouse, touch (mobile), delay to prevent accidental drags

+    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),

+    useSensor(TouchSensor,   { activationConstraint: { delay: 180, tolerance: 6 } })

+  const onDragStart = ({ active }) => {

+    setActiveTask(allTasks.find(t => t.id === active.id) || null);

+  const onDragEnd = async ({ active, over }) => {

+    const task = allTasks.find(t => t.id === active.id);

+    const targetCol = COLUMNS.find(c => c.id === over.id);

+    if (!targetCol || getColumnId(task) === targetCol.id) return;

+    const updated = columnUpdates(targetCol.id, task);

+    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, ...updated } : t));

+      await api.put(`/tasks/${task.id}`, updated);

+      toast.success(`Moved to "${targetCol.title}"`);

+      toast.error('Failed to move task'); load();

+    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'Done' } : t));

await api.patch(`/tasks/${task.id}/status`, { status: 'Done' });

-  const openNew = (defaults = {}) => { setNewTaskDefaults(defaults); setShowNewTask(true); };

+  const openNew = (defaults = {}) => { setNewDefaults(defaults); setShowNew(true); };

-      else { await api.post('/tasks', { ...form, ...newTaskDefaults }); toast.success('Task added'); }

-      setEditTask(null); setShowNewTask(false); load();

+      else { await api.post('/tasks', { ...form, ...newDefaults }); toast.success('Task added'); }

+      setEditTask(null); setShowNew(false); load();

-    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');

+    await api.delete(`/tasks/${deleteTask.id}`);

+    toast.success('Deleted'); setDeleteTask(null); load();

{ id: 'dashboard', label: 'Dashboard' },

-    { id: 'focus',     label: 'Today\'s Focus' },

-    { id: 'all',       label: 'All Tasks' },

-    { id: 'projects',  label: 'Projects' },

+    { id: 'all',       label: 'All Tasks'      },

+    { id: 'projects',  label: 'Projects'       },

<div className="flex flex-col h-full overflow-hidden">

-      {/* ── Hero Banner ─────────────────────────────────────────────── */}

-      <div className="relative overflow-hidden bg-hero-gradient mx-4 mt-4 rounded-2xl px-6 py-5 shadow-card">

-        <div className="blob w-48 h-48 bg-violet-400 -top-12 right-16" style={{animationDelay:'0s'}} />

-        <div className="blob w-36 h-36 bg-pink-400 top-4 right-4" style={{animationDelay:'2s'}} />

-        <div className="blob w-32 h-32 bg-amber-300 -bottom-8 right-40" style={{animationDelay:'4s'}} />

-        <div className="relative z-10 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">

-            <div className="flex items-center gap-2.5 mb-1">

-              <div className="w-9 h-9 bg-white/80 backdrop-blur rounded-xl flex items-center justify-center shadow-sm">

-                <Zap size={18} className="text-violet-600" />

+      <div className="relative overflow-hidden bg-hero-gradient mx-3 mt-3 rounded-2xl px-5 py-4 shadow-card shrink-0">

+        <div className="blob w-48 h-48 bg-violet-400 -top-12 right-16" style={{ animationDelay: '0s' }} />

+        <div className="blob w-36 h-36 bg-pink-400 top-2 right-2"  style={{ animationDelay: '2s' }} />

+        <div className="blob w-28 h-28 bg-amber-300 -bottom-6 right-44" style={{ animationDelay: '4s' }} />

+        <div className="relative z-10 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3">

+          <div className="flex items-center gap-2.5">

+            <div className="w-9 h-9 bg-white/80 backdrop-blur rounded-xl flex items-center justify-center shadow-sm shrink-0">

+              <Zap size={17} className="text-violet-600" />

-          <div className="flex items-center gap-4 sm:gap-6">

+          <div className="flex items-center gap-3 sm:gap-5 flex-wrap">

-              { label: 'Active Projects', value: stats?.activeProjects ?? '—', Icon: FolderKanban },

-              { label: 'Open Tasks',      value: stats?.openTasks ?? '—',      Icon: CheckSquare  },

-              { label: 'Follow-ups',      value: stats?.openFollowUps ?? '—',  Icon: Bell         },

-              { label: "Today's Focus",   value: stats?.todayFocus ?? '—',     Icon: Target       },

+              { label: 'Projects',     value: stats?.activeProjects ?? '—', Icon: FolderKanban },

+              { label: 'Open Tasks',   value: stats?.openTasks      ?? '—', Icon: CheckSquare  },

+              { label: 'Follow-ups',   value: stats?.openFollowUps  ?? '—', Icon: Bell         },

+              { label: "Today's Focus",value: stats?.todayFocus     ?? '—', Icon: Target       },

-              <div key={label} className="text-center">

-                <p className="text-[10px] text-gray-600 mt-0.5 whitespace-nowrap flex items-center justify-center gap-1">

-                  <Icon size={10} />{label}

+              <div key={label} className="text-center min-w-[48px]">

+                <p className="text-[10px] text-gray-600 mt-0.5 flex items-center justify-center gap-0.5 whitespace-nowrap">

+                  <Icon size={9} />{label}

-      {/* ── Tabs ────────────────────────────────────────────────────── */}

-      <div className="flex items-center gap-1 px-4 pt-3 pb-0">

+      <div className="flex items-center gap-1 px-3 pt-2.5 pb-0 shrink-0">

-            onClick={() => setActiveTab(t.id)}

-            className={`px-4 py-2 rounded-xl text-sm font-medium transition-all duration-150 ${

+          <button key={t.id} onClick={() => setActiveTab(t.id)}

+            className={`px-3.5 py-1.5 rounded-xl text-sm font-medium transition-all duration-150 ${

-        <button onClick={() => openNew({ is_today_focus: 1 })} className="btn-primary flex items-center gap-1.5 py-2 text-xs">

+        <button onClick={() => openNew({ is_today_focus: 1 })} className="btn-primary flex items-center gap-1 py-1.5 text-xs">

-      {/* ── Tab Content ─────────────────────────────────────────────── */}

+      {/* ── Kanban Board (drag & drop) ─────────────────────────────────── */}

-        <div className="flex gap-3 px-4 py-3 overflow-x-auto">

-          {[1,2,3].map(i => <div key={i} className="skeleton h-64 w-[270px] shrink-0 rounded-2xl" />)}

+        <div className="flex gap-3 px-3 py-3 overflow-x-auto">

+          {[1,2,3,4].map(i => <div key={i} className="skeleton rounded-2xl shrink-0" style={{ width: 270, height: 300 }} />)}

-          {(activeTab === 'dashboard' || activeTab === 'focus') && (

-            <div className="flex gap-3 px-4 py-3 overflow-x-auto flex-1 min-h-0">

-                count={focusTasks.length}

-                tasks={activeTab === 'focus' ? focusTasks : focusTasks}

-                color="bg-primary/15 text-primary"

-                onAddTask={() => openNew({ is_today_focus: 1 })}

-                onDelete={setDeleteTask}

-                onToggleFocus={toggleFocus}

-                emptyText="No tasks pinned for today. Pin urgent tasks!"

-                count={inProgressTasks.length}

-                tasks={inProgressTasks}

-                color="bg-blue-100 text-blue-600"

-                onAddTask={() => openNew({ status: 'In Progress' })}

-                emptyText="No tasks in progress"

-                count={followUpTasks.length}

-                color="bg-amber-100 text-amber-600"

-                onAddTask={() => openNew({ is_follow_up: 1 })}

-                emptyText="No open follow-ups"

+          {activeTab === 'dashboard' && (

+            <DndContext sensors={sensors} collisionDetection={closestCenter} onDragStart={onDragStart} onDragEnd={onDragEnd}>

+              {/* Horizontal scrollable kanban — snaps on mobile */}

+              <div className="flex gap-3 px-3 py-3 overflow-x-auto flex-1 min-h-0"

+                style={{ scrollSnapType: 'x mandatory', WebkitOverflowScrolling: 'touch' }}>

+                    key={col.id} col={col} tasks={col.tasks}

+                    onAddTask={() => openNew(

+                      col.id === 'focus'      ? { is_today_focus: 1 } :

+                      col.id === 'inprogress' ? { status: 'In Progress' } :

+                      col.id === 'followups'  ? { is_follow_up: 1 } : {}

+                    onEdit={setEditTask}

+                    onDelete={setDeleteTask}

+                    onMarkDone={markDone}

+              <DragOverlay dropAnimation={{ duration: 180, easing: 'cubic-bezier(0.18,0.67,0.6,1.22)' }}>

+                {activeTask && <OverlayCard task={activeTask} />}

-          {/* ALL TASKS — flat list */}

+          {/* ALL TASKS — horizontal grid */}

-            <div className="flex-1 overflow-y-auto px-4 py-3">

-              <div className="max-w-2xl space-y-2">

+            <div className="flex-1 overflow-y-auto px-3 py-3">

+              <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2.5">

{allTasks.filter(t => t.status !== 'Done').map(task => (

-                    className={`kanban-card border-l-4 ${

-                      {Urgent:'border-l-red-500',High:'border-l-amber-400',Medium:'border-l-blue-400',Low:'border-l-green-400'}[task.priority]

-                    } group cursor-default`}

-                    onClick={() => setEditTask(task)}

-                    <div className="flex items-center gap-3">

-                      <button onClick={e => { e.stopPropagation(); toggleFocus(task); }}

-                        className={`shrink-0 w-5 h-5 rounded-full border-2 transition-all ${task.is_today_focus ? 'bg-primary border-primary' : 'border-gray-300 hover:border-primary'}`} />

-                      <div className="flex gap-1.5">

-                        <span className={`badge text-[10px] ${getPriorityClass(task.priority)}`}>{task.priority}

-                        {task.assignee && {task.assignee}}

+                    className={`bg-white dark:bg-gray-900 rounded-xl border border-gray-100 dark:border-gray-800 border-l-4

+                      ${PRIORITY_BORDER[task.priority]} shadow-card hover:shadow-hover transition-all duration-150 hover:-translate-y-0.5 cursor-pointer p-3`}

+                    onClick={() => setEditTask(task)}>

+                    <div className="flex flex-wrap gap-1 mb-2">

+                      <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}

+                      <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>

+                        {CATEGORIES[task.category]?.label?.split(' ')[0]}

+                    {task.assignee && (

+                      <div className="flex items-center gap-1.5">

+                        <div className="w-5 h-5 rounded-full bg-gradient-to-br from-primary to-brand-pink flex items-center justify-center text-white text-[9px] font-bold">

+                          {task.assignee[0].toUpperCase()}

+                        {task.assignee}

+          {/* PROJECTS — horizontal grid */}

-            <div className="flex-1 overflow-y-auto px-4 py-3">

-              <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 max-w-4xl">

+            <div className="flex-1 overflow-y-auto px-3 py-3">

+              <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2.5">

{projects.filter(p => p.status !== 'Done').map(p => (

-                    onClick={() => navigate(`/projects/${p.id}`)}

-                    className="card-hover text-left p-4 group"

+                  <button key={p.id} onClick={() => navigate(`/projects/${p.id}`)}

+                    className="card-hover text-left p-4 group">

<div className="flex items-start justify-between mb-2">

-                      <span className={`badge text-[10px] ${getCategoryClass(p.category)}`}>{CATEGORIES[p.category]?.label || p.category}

-                      <ArrowRight size={13} className="text-gray-300 group-hover:text-primary transition-colors" />

+                      <span className={`badge text-[10px] ${getCategoryClass(p.category)}`}>

+                        {CATEGORIES[p.category]?.label?.split(' ')[0] || p.category}

+                      <ArrowRight size={12} className="text-gray-300 group-hover:text-primary transition-colors" />

-                    <div className="flex items-center justify-between text-xs text-gray-400">

-                      <span className={`font-medium ${p.priority === 'Urgent' ? 'text-red-500' : p.priority === 'High' ? 'text-amber-500' : ''}`}>{p.priority}

+                    <div className="flex items-center justify-between text-[10px] text-gray-400">

+                      <span className={`font-semibold ${p.priority === 'Urgent' ? 'text-red-500' : p.priority === 'High' ? 'text-amber-500' : ''}`}>{p.priority}

-        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNewTask(false); setEditTask(null); }} />

+        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />

import { useState, useEffect, useCallback } from 'react';
import { Plus, MoreHorizontal, User, Calendar, Zap, ArrowRight, FolderKanban, CheckSquare, Bell, Target, AlertTriangle } from 'lucide-react';
import { Link, useNavigate } from 'react-router-dom';
import toast from 'react-hot-toast';
import api from '../api';
import TaskModal from './TaskModal';
import ConfirmDialog from './ConfirmDialog';
import { getCategoryClass, getPriorityClass, CATEGORIES, formatDate, isOverdue } from '../utils';

// ─── Kanban Task Card ───────────────────────────────────────────────────────
function KanbanCard({ task, onEdit, onDelete, onToggleFocus, onMarkDone }) {
  const overdue = isOverdue(task.due_date) && task.status !== 'Done';
  const priorityBorder = {
    Urgent: 'border-l-red-500',
    High:   'border-l-amber-400',
    Medium: 'border-l-blue-400',
    Low:    'border-l-green-400',
  }[task.priority] || 'border-l-gray-200';

  return (
    <div className={`kanban-card border-l-4 ${priorityBorder} group`}>
      {/* Top row */}

{task.title}

        <button
          onClick={() => onEdit(task)}
          className="shrink-0 opacity-0 group-hover:opacity-100 p-1 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-400 transition-all"
        >
          <MoreHorizontal size={14} />
        </button>

      {/* Notes preview */}
      {task.notes && (

{task.notes}

      )}

      {/* Tags */}

        <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
          {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}

        <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
        {task.is_follow_up === 1 && (
          Follow-up
        )}

      {/* Footer */}

          {task.assignee ? (

              {task.assignee[0]?.toUpperCase()}

          ) : (

              <User size={10} className="text-gray-400" />

          )}
          {task.assignee && {task.assignee}}

          {task.due_date && (
            <span className={`flex items-center gap-1 text-[10px] ${overdue ? 'text-red-500 font-semibold' : 'text-gray-400'}`}>
              <Calendar size={10} />
              {overdue && <AlertTriangle size={10} className="text-red-500" />}{formatDate(task.due_date)}

          )}
          {task.status !== 'Done' && (
            <button
              onClick={() => onMarkDone(task)}
              className="opacity-0 group-hover:opacity-100 text-[10px] px-2 py-0.5 bg-green-100 text-green-700 rounded-full hover:bg-green-200 transition-all font-medium"
            >
              Done
            </button>
          )}

  );
}

// ─── Kanban Column ──────────────────────────────────────────────────────────
function KanbanColumn({ title, count, tasks, color, onAddTask, onEdit, onDelete, onToggleFocus, onMarkDone, emptyText }) {
  return (

      {/* Column header */}

{title}

          <span className={`text-xs font-bold px-2 py-0.5 rounded-full ${color}`}>{count}

        <button onClick={onAddTask} className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all shadow-sm">
          <Plus size={12} />
        </button>

      {/* Cards */}

        {tasks.length === 0 ? (

{emptyText}

        ) : (
          tasks.map(task => (
            <KanbanCard
              key={task.id}
              task={task}
              onEdit={onEdit}
              onDelete={onDelete}
              onToggleFocus={onToggleFocus}
              onMarkDone={onMarkDone}
            />
          ))
        )}

  );
}

// ─── Main Component ─────────────────────────────────────────────────────────
export default function Today() {
  const [allTasks, setAllTasks] = useState([]);
  const [stats, setStats] = useState(null);
  const [projects, setProjects] = useState([]);
  const [loading, setLoading] = useState(true);
  const [editTask, setEditTask] = useState(null);
  const [deleteTask, setDeleteTask] = useState(null);
  const [showNewTask, setShowNewTask] = useState(false);
  const [newTaskDefaults, setNewTaskDefaults] = useState({});
  const [activeTab, setActiveTab] = useState('dashboard');
  const navigate = useNavigate();

  const today = new Date();
  const dateLabel = today.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });

  const load = useCallback(async () => {
    try {
      const [tasks, st, pr] = await Promise.all([
        api.get('/tasks'),
        api.get('/tasks/stats'),
        api.get('/projects'),
      ]);
      setAllTasks(tasks);
      setStats(st);
      setProjects(pr);
    } finally { setLoading(false); }
  }, []);

  useEffect(() => { load(); }, [load]);

  // ── Kanban buckets ──────────────────────────────────────────────────────
  const focusTasks     = allTasks.filter(t => t.is_today_focus && t.status !== 'Done');
  const inProgressTasks = allTasks.filter(t => !t.is_today_focus && t.status === 'In Progress');
  const followUpTasks  = allTasks.filter(t => t.is_follow_up && t.status !== 'Done' && !t.is_today_focus);

  // ── Handlers ────────────────────────────────────────────────────────────
  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };
  const markDone    = async (task) => {
    await api.patch(`/tasks/${task.id}/status`, { status: 'Done' });
    toast.success('✓ Marked as done');
    load();
  };
  const openNew = (defaults = {}) => { setNewTaskDefaults(defaults); setShowNewTask(true); };
  const handleSave = async (form) => {
    try {
      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
      else { await api.post('/tasks', { ...form, ...newTaskDefaults }); toast.success('Task added'); }
      setEditTask(null); setShowNewTask(false); load();
    } catch (e) { toast.error(e.message); }
  };
  const handleDelete = async () => {
    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');
    setDeleteTask(null); load();
  };

  const TABS = [
    { id: 'dashboard', label: 'Dashboard' },
    { id: 'focus',     label: 'Today\'s Focus' },
    { id: 'all',       label: 'All Tasks' },
    { id: 'projects',  label: 'Projects' },
  ];

  return (

      {/* ── Hero Banner ─────────────────────────────────────────────── */}

        {/* Blobs */}

                <Zap size={18} className="text-violet-600" />

DEWA AI Workspace

{dateLabel}

          {/* Stats row */}

            {[
              { label: 'Active Projects', value: stats?.activeProjects ?? '—', Icon: FolderKanban },
              { label: 'Open Tasks',      value: stats?.openTasks ?? '—',      Icon: CheckSquare  },
              { label: 'Follow-ups',      value: stats?.openFollowUps ?? '—',  Icon: Bell         },
              { label: "Today's Focus",   value: stats?.todayFocus ?? '—',     Icon: Target       },
            ].map(({ label, value, Icon }) => (

{value}

                  <Icon size={10} />{label}

            ))}

      {/* ── Tabs ────────────────────────────────────────────────────── */}

        {TABS.map(t => (
          <button
            key={t.id}
            onClick={() => setActiveTab(t.id)}
            className={`px-4 py-2 rounded-xl text-sm font-medium transition-all duration-150 ${
              activeTab === t.id
                ? 'bg-primary text-white shadow-sm'
                : 'text-gray-500 dark:text-gray-400 hover:bg-white dark:hover:bg-gray-800 hover:text-gray-800 dark:hover:text-white'
            }`}
          >
            {t.label}
          </button>
        ))}

        <button onClick={() => openNew({ is_today_focus: 1 })} className="btn-primary flex items-center gap-1.5 py-2 text-xs">
          <Plus size={13} /> New Task
        </button>

      {/* ── Tab Content ─────────────────────────────────────────────── */}
      {loading ? (

          {[1,2,3].map(i =>
)}

      ) : (
        <>
          {/* DASHBOARD — Kanban */}
          {(activeTab === 'dashboard' || activeTab === 'focus') && (

              <KanbanColumn
                title="Today's Focus"
                count={focusTasks.length}
                tasks={activeTab === 'focus' ? focusTasks : focusTasks}
                color="bg-primary/15 text-primary"
                onAddTask={() => openNew({ is_today_focus: 1 })}
                onEdit={setEditTask}
                onDelete={setDeleteTask}
                onToggleFocus={toggleFocus}
                onMarkDone={markDone}
                emptyText="No tasks pinned for today. Pin urgent tasks!"
              />
              <KanbanColumn
                title="In Progress"
                count={inProgressTasks.length}
                tasks={inProgressTasks}
                color="bg-blue-100 text-blue-600"
                onAddTask={() => openNew({ status: 'In Progress' })}
                onEdit={setEditTask}
                onDelete={setDeleteTask}
                onToggleFocus={toggleFocus}
                onMarkDone={markDone}
                emptyText="No tasks in progress"
              />
              <KanbanColumn
                title="Follow-ups"
                count={followUpTasks.length}
                tasks={followUpTasks}
                color="bg-amber-100 text-amber-600"
                onAddTask={() => openNew({ is_follow_up: 1 })}
                onEdit={setEditTask}
                onDelete={setDeleteTask}
                onToggleFocus={toggleFocus}
                onMarkDone={markDone}
                emptyText="No open follow-ups"
              />

          )}

          {/* ALL TASKS — flat list */}
          {activeTab === 'all' && (

                {allTasks.filter(t => t.status !== 'Done').map(task => (

 setEditTask(task)}
                  >

                      <button onClick={e => { e.stopPropagation(); toggleFocus(task); }}
                        className={`shrink-0 w-5 h-5 rounded-full border-2 transition-all ${task.is_today_focus ? 'bg-primary border-primary' : 'border-gray-300 hover:border-primary'}`} />

{task.title}

                        <span className={`badge text-[10px] ${getPriorityClass(task.priority)}`}>{task.priority}
                        {task.assignee && {task.assignee}}

                ))}

          )}

          {/* PROJECTS — grid */}
          {activeTab === 'projects' && (

                {projects.filter(p => p.status !== 'Done').map(p => (
                  <button
                    key={p.id}
                    onClick={() => navigate(`/projects/${p.id}`)}
                    className="card-hover text-left p-4 group"
                  >

                      <span className={`badge text-[10px] ${getCategoryClass(p.category)}`}>{CATEGORIES[p.category]?.label || p.category}
                      <ArrowRight size={13} className="text-gray-300 group-hover:text-primary transition-colors" />

{p.name}

                      <span className={`font-medium ${p.priority === 'Urgent' ? 'text-red-500' : p.priority === 'High' ? 'text-amber-500' : ''}`}>{p.priority}
                      {p.open_task_count || 0} tasks

                  </button>
                ))}

          )}
        </>
      )}

      {/* Modals */}
      {(showNewTask || editTask) && (
        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNewTask(false); setEditTask(null); }} />
      )}
      {deleteTask && (
        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
      )}

  );
}


Write

import { useState, useEffect, useRef } from 'react';
import { Plus, Search, SlidersHorizontal, CheckSquare, X } from 'lucide-react';
import toast from 'react-hot-toast';
import api from '../api';
import TaskCard from './TaskCard';
import TaskModal from './TaskModal';
import ConfirmDialog from './ConfirmDialog';
import { CATEGORIES, STATUSES, PRIORITIES } from '../utils';

function useDebounce(v, d = 300) {
  const [dv, setDv] = useState(v);
  useEffect(() => { const t = setTimeout(() => setDv(v), d); return () => clearTimeout(t); }, [v, d]);
  return dv;
}

// Status columns for horizontal kanban-style layout
const STATUS_COLS = [
  { id: '',          label: 'All',         color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
  { id: 'Open',      label: 'Open',        color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
  { id: 'In Progress',label:'In Progress', color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' },
  { id: 'Waiting',   label: 'Waiting',     color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300' },
  { id: 'Done',      label: 'Done',        color: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' },
];

export default function Tasks() {
  const [tasks, setTasks]           = useState([]);
  const [projects, setProjects]     = useState([]);
  const [loading, setLoading]       = useState(true);
  const [search, setSearch]         = useState('');
  const [statusFilter, setStatus]   = useState('');
  const [catFilter, setCat]         = useState('');
  const [priorityFilter, setPri]    = useState('');
  const [showFilters, setShowFilters] = useState(false);
  const [editTask, setEditTask]     = useState(null);
  const [deleteTask, setDeleteTask] = useState(null);
  const [showNew, setShowNew]       = useState(false);
  const [selected, setSelected]     = useState(new Set());
  const [viewMode, setViewMode]     = useState('grid'); // 'grid' | 'kanban'
  const debouncedSearch = useDebounce(search);

  const load = async () => {
    setLoading(true);
    const p = new URLSearchParams();
    if (debouncedSearch)  p.set('search',   debouncedSearch);
    if (statusFilter)     p.set('status',   statusFilter);
    if (catFilter)        p.set('category', catFilter);
    if (priorityFilter)   p.set('priority', priorityFilter);
    try {
      const [t, pr] = await Promise.all([api.get('/tasks?' + p), api.get('/projects')]);
      setTasks(t); setProjects(pr);
    } finally { setLoading(false); }
  };

  useEffect(() => { load(); }, [debouncedSearch, statusFilter, catFilter, priorityFilter]);

  const handleSave = async (form) => {
    try {
      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
      else              { await api.post('/tasks', form);               toast.success('Task added');   }
      setEditTask(null); setShowNew(false); load();
    } catch (e) { toast.error(e.message); }
  };

  const handleDelete = async () => {
    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');
    setDeleteTask(null); load();
  };

  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };

  const toggleSelect = (id) => setSelected(s => {
    const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n;
  });

  const bulkDone = async () => {
    await Promise.all([...selected].map(id => api.patch(`/tasks/${id}/status`, { status: 'Done' })));
    toast.success(`${selected.size} tasks done`);
    setSelected(new Set()); load();
  };

  const hasFilters = statusFilter || catFilter || priorityFilter;

  // Kanban grouping by status
  const KANBAN_COLS = ['Open', 'In Progress', 'Waiting', 'Done'];
  const byStatus = KANBAN_COLS.reduce((acc, s) => {
    acc[s] = tasks.filter(t => t.status === s);
    return acc;
  }, {});

  return (

      {/* Header */}

Tasks

            {/* View toggle */}

              {[{ id:'grid', label:'Grid' }, { id:'kanban', label:'Board' }].map(v => (
                <button key={v.id} onClick={() => setViewMode(v.id)}
                  className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
                    viewMode === v.id ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500'
                  }`}>
                  {v.label}
                </button>
              ))}

            <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5 py-2">
              <Plus size={14} /> New Task
            </button>

        {/* Search + filter row */}

            <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
            <input className="input pl-8 py-2 text-sm" placeholder="Search tasks…" value={search} onChange={e => setSearch(e.target.value)} />

          <button onClick={() => setShowFilters(!showFilters)}
            className={`btn-secondary flex items-center gap-1.5 py-2 text-sm ${hasFilters ? 'border-primary text-primary' : ''}`}>
            <SlidersHorizontal size={13} />
            {hasFilters ? 'Filtered' : 'Filter'}
          </button>

        {/* Filter chips */}
        {showFilters && (

            <select className="select text-xs py-1.5 w-auto" value={statusFilter} onChange={e => setStatus(e.target.value)}>
              <option value="">All Status</option>
              {STATUSES.map(s => <option key={s}>{s}</option>)}
            </select>
            <select className="select text-xs py-1.5 w-auto" value={catFilter} onChange={e => setCat(e.target.value)}>
              <option value="">All Categories</option>
              {Object.entries(CATEGORIES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
            </select>
            <select className="select text-xs py-1.5 w-auto" value={priorityFilter} onChange={e => setPri(e.target.value)}>
              <option value="">All Priorities</option>
              {PRIORITIES.map(p => <option key={p}>{p}</option>)}
            </select>
            {hasFilters && (
              <button onClick={() => { setStatus(''); setCat(''); setPri(''); }}
                className="flex items-center gap-1 text-xs text-primary hover:underline px-2">
                <X size={11} /> Clear
              </button>
            )}

        )}

        {/* Bulk actions */}
        {selected.size > 0 && (

            {selected.size} selected
            <button onClick={bulkDone} className="btn-primary py-1 text-xs flex items-center gap-1">
              <CheckSquare size={11} /> Mark done
            </button>
            <button onClick={() => setSelected(new Set())} className="btn-ghost text-xs">Clear</button>

        )}

      {/* Content area */}
      {loading ? (

          {[...Array(8)].map((_, i) =>
)}

      ) : tasks.length === 0 ? (

          <CheckSquare size={40} className="text-gray-200 dark:text-gray-700" />

No tasks found

          {(search || hasFilters) && (
            <button onClick={() => { setSearch(''); setStatus(''); setCat(''); setPri(''); }} className="btn-secondary text-sm">
              Clear filters
            </button>
          )}

      ) : viewMode === 'grid' ? (
        /* ── GRID view ─────────────────────────────────── */

{tasks.length} task{tasks.length !== 1 ? 's' : ''}

            {tasks.map(task => (

                <input type="checkbox" className="absolute top-3 left-3 z-10 w-3.5 h-3.5 accent-primary cursor-pointer rounded"
                  checked={selected.has(task.id)} onChange={() => toggleSelect(task.id)} />

                  <TaskCard task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

            ))}

      ) : (
        /* ── KANBAN / BOARD view ────────────────────────── */

          {KANBAN_COLS.map(status => {
            const col = STATUS_COLS.find(c => c.id === status);
            const colTasks = byStatus[status] || [];
            return (

{status}

                    <span className={`badge text-[10px] py-0.5 ${col?.color}`}>{colTasks.length}

                  <button onClick={() => setShowNew(true)}
                    className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all">
                    <Plus size={12} />
                  </button>

                  {colTasks.map(task => (
                    <TaskCard key={task.id} task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />
                  ))}
                  {colTasks.length === 0 && (

No tasks

                  )}

            );
          })}

      )}

      {(showNew || editTask) && (
        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />
      )}
      {deleteTask && (
        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
      )}

  );
}


The file /Users/khalidbinkalban/my-workspace/client/src/components/Tasks.jsx has been updated successfully.

import { useState, useEffect, useRef } from 'react';
import { Plus, Search, SlidersHorizontal, CheckSquare, X } from 'lucide-react';
import toast from 'react-hot-toast';
import api from '../api';
import TaskCard from './TaskCard';
import TaskModal from './TaskModal';
import ConfirmDialog from './ConfirmDialog';
import { CATEGORIES, STATUSES, PRIORITIES } from '../utils';

function useDebounce(v, d = 300) {
  const [dv, setDv] = useState(v);
  useEffect(() => { const t = setTimeout(() => setDv(v), d); return () => clearTimeout(t); }, [v, d]);
  return dv;
}

// Status columns for horizontal kanban-style layout
const STATUS_COLS = [
  { id: '',          label: 'All',         color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
  { id: 'Open',      label: 'Open',        color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
  { id: 'In Progress',label:'In Progress', color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' },
  { id: 'Waiting',   label: 'Waiting',     color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300' },
  { id: 'Done',      label: 'Done',        color: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' },
];

export default function Tasks() {
  const [tasks, setTasks]           = useState([]);
  const [projects, setProjects]     = useState([]);
  const [loading, setLoading]       = useState(true);
  const [search, setSearch]         = useState('');
  const [statusFilter, setStatus]   = useState('');
  const [catFilter, setCat]         = useState('');
  const [priorityFilter, setPri]    = useState('');
  const [showFilters, setShowFilters] = useState(false);
  const [editTask, setEditTask]     = useState(null);
  const [deleteTask, setDeleteTask] = useState(null);
  const [showNew, setShowNew]       = useState(false);
  const [selected, setSelected]     = useState(new Set());
  const [viewMode, setViewMode]     = useState('grid'); // 'grid' | 'kanban'
  const debouncedSearch = useDebounce(search);

  const load = async () => {
    setLoading(true);
    const p = new URLSearchParams();
    if (debouncedSearch)  p.set('search',   debouncedSearch);
    if (statusFilter)     p.set('status',   statusFilter);
    if (catFilter)        p.set('category', catFilter);
    if (priorityFilter)   p.set('priority', priorityFilter);
    try {
      const [t, pr] = await Promise.all([api.get('/tasks?' + p), api.get('/projects')]);
      setTasks(t); setProjects(pr);
    } finally { setLoading(false); }
  };

  useEffect(() => { load(); }, [debouncedSearch, statusFilter, catFilter, priorityFilter]);

  const handleSave = async (form) => {
    try {
      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
      else              { await api.post('/tasks', form);               toast.success('Task added');   }
      setEditTask(null); setShowNew(false); load();
    } catch (e) { toast.error(e.message); }
  };

  const handleDelete = async () => {
    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');
    setDeleteTask(null); load();
  };

  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };

  const toggleSelect = (id) => setSelected(s => {
    const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n;
  });

  const bulkDone = async () => {
    await Promise.all([...selected].map(id => api.patch(`/tasks/${id}/status`, { status: 'Done' })));
    toast.success(`${selected.size} tasks done`);
    setSelected(new Set()); load();
  };

  const hasFilters = statusFilter || catFilter || priorityFilter;

  // Kanban grouping by status
  const KANBAN_COLS = ['Open', 'In Progress', 'Waiting', 'Done'];
  const byStatus = KANBAN_COLS.reduce((acc, s) => {
    acc[s] = tasks.filter(t => t.status === s);
    return acc;
  }, {});

  return (

      {/* Header */}

Tasks

            {/* View toggle */}

              {[{ id:'grid', label:'Grid' }, { id:'kanban', label:'Board' }].map(v => (
                <button key={v.id} onClick={() => setViewMode(v.id)}
                  className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
                    viewMode === v.id ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500'
                  }`}>
                  {v.label}
                </button>
              ))}

            <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5 py-2">
              <Plus size={14} /> New Task
            </button>

        {/* Search + filter row */}

            <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
            <input className="input pl-8 py-2 text-sm" placeholder="Search tasks…" value={search} onChange={e => setSearch(e.target.value)} />

          <button onClick={() => setShowFilters(!showFilters)}
            className={`btn-secondary flex items-center gap-1.5 py-2 text-sm ${hasFilters ? 'border-primary text-primary' : ''}`}>
            <SlidersHorizontal size={13} />
            {hasFilters ? 'Filtered' : 'Filter'}
          </button>

        {/* Filter chips */}
        {showFilters && (

            <select className="select text-xs py-1.5 w-auto" value={statusFilter} onChange={e => setStatus(e.target.value)}>
              <option value="">All Status</option>
              {STATUSES.map(s => <option key={s}>{s}</option>)}
            </select>
            <select className="select text-xs py-1.5 w-auto" value={catFilter} onChange={e => setCat(e.target.value)}>
              <option value="">All Categories</option>
              {Object.entries(CATEGORIES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
            </select>
            <select className="select text-xs py-1.5 w-auto" value={priorityFilter} onChange={e => setPri(e.target.value)}>
              <option value="">All Priorities</option>
              {PRIORITIES.map(p => <option key={p}>{p}</option>)}
            </select>
            {hasFilters && (
              <button onClick={() => { setStatus(''); setCat(''); setPri(''); }}
                className="flex items-center gap-1 text-xs text-primary hover:underline px-2">
                <X size={11} /> Clear
              </button>
            )}

        )}

        {/* Bulk actions */}
        {selected.size > 0 && (

            {selected.size} selected
            <button onClick={bulkDone} className="btn-primary py-1 text-xs flex items-center gap-1">
              <CheckSquare size={11} /> Mark done
            </button>
            <button onClick={() => setSelected(new Set())} className="btn-ghost text-xs">Clear</button>

        )}

      {/* Content area */}
      {loading ? (

          {[...Array(8)].map((_, i) =>
)}

      ) : tasks.length === 0 ? (

          <CheckSquare size={40} className="text-gray-200 dark:text-gray-700" />

No tasks found

          {(search || hasFilters) && (
            <button onClick={() => { setSearch(''); setStatus(''); setCat(''); setPri(''); }} className="btn-secondary text-sm">
              Clear filters
            </button>
          )}

      ) : viewMode === 'grid' ? (
        /* ── GRID view ─────────────────────────────────── */

{tasks.length} task{tasks.length !== 1 ? 's' : ''}

            {tasks.map(task => (

                <input type="checkbox" className="absolute top-3 left-3 z-10 w-3.5 h-3.5 accent-primary cursor-pointer rounded"
                  checked={selected.has(task.id)} onChange={() => toggleSelect(task.id)} />

                  <TaskCard task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

            ))}

      ) : (
        /* ── KANBAN / BOARD view ────────────────────────── */

          {KANBAN_COLS.map(status => {
            const col = STATUS_COLS.find(c => c.id === status);
            const colTasks = byStatus[status] || [];
            return (

{status}

                    <span className={`badge text-[10px] py-0.5 ${col?.color}`}>{colTasks.length}

                  <button onClick={() => setShowNew(true)}
                    className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all">
                    <Plus size={12} />
                  </button>

                  {colTasks.map(task => (
                    <TaskCard key={task.id} task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />
                  ))}
                  {colTasks.length === 0 && (

No tasks

                  )}

            );
          })}

      )}

      {(showNew || editTask) && (
        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />
      )}
      {deleteTask && (
        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
      )}

  );
}

import { useState, useEffect, useRef } from 'react';

-import { Plus, Search, Filter, CheckSquare } from 'lucide-react';

+import { Plus, Search, SlidersHorizontal, CheckSquare, X } from 'lucide-react';

import ConfirmDialog from './ConfirmDialog';

-import { CATEGORIES, STATUSES, PRIORITIES, getCategoryClass, getPriorityClass } from '../utils';

+import { CATEGORIES, STATUSES, PRIORITIES } from '../utils';

-  { value: 'priority', label: 'Priority' },

-  { value: 'due_date', label: 'Due Date' },

-  { value: 'created_at', label: 'Created' },

-function useDebounce(value, delay = 300) {

-  useEffect(() => { const t = setTimeout(() => setDv(value), delay); return () => clearTimeout(t); }, [value, delay]);

+  useEffect(() => { const t = setTimeout(() => setDv(v), d); return () => clearTimeout(t); }, [v, d]);

+// Status columns for horizontal kanban-style layout

+  { id: '',          label: 'All',         color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },

+  { id: 'Open',      label: 'Open',        color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },

+  { id: 'In Progress',label:'In Progress', color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' },

+  { id: 'Waiting',   label: 'Waiting',     color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300' },

+  { id: 'Done',      label: 'Done',        color: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' },

-  const [tasks, setTasks] = useState([]);

-  const [projects, setProjects] = useState([]);

-  const [loading, setLoading] = useState(true);

-  const [search, setSearch] = useState('');

-  const [statusFilter, setStatusFilter] = useState('');

-  const [catFilter, setCatFilter] = useState('');

-  const [priorityFilter, setPriorityFilter] = useState('');

-  const [editTask, setEditTask] = useState(null);

-  const [deleteTask, setDeleteTask] = useState(null);

-  const [showNew, setShowNew] = useState(false);

-  const [selected, setSelected] = useState(new Set());

+  const [tasks, setTasks]           = useState([]);

+  const [projects, setProjects]     = useState([]);

+  const [loading, setLoading]       = useState(true);

+  const [search, setSearch]         = useState('');

+  const [statusFilter, setStatus]   = useState('');

+  const [catFilter, setCat]         = useState('');

+  const [priorityFilter, setPri]    = useState('');

const [showFilters, setShowFilters] = useState(false);

+  const [editTask, setEditTask]     = useState(null);

+  const [deleteTask, setDeleteTask] = useState(null);

+  const [showNew, setShowNew]       = useState(false);

+  const [selected, setSelected]     = useState(new Set());

+  const [viewMode, setViewMode]     = useState('grid'); // 'grid' | 'kanban'

const debouncedSearch = useDebounce(search);

-    const params = new URLSearchParams();

-    if (debouncedSearch) params.set('search', debouncedSearch);

-    if (statusFilter) params.set('status', statusFilter);

-    if (catFilter) params.set('category', catFilter);

-    if (priorityFilter) params.set('priority', priorityFilter);

+    if (debouncedSearch)  p.set('search',   debouncedSearch);

+    if (statusFilter)     p.set('status',   statusFilter);

+    if (catFilter)        p.set('category', catFilter);

+    if (priorityFilter)   p.set('priority', priorityFilter);

-      const [t, pr] = await Promise.all([api.get('/tasks?' + params), api.get('/projects')]);

+      const [t, pr] = await Promise.all([api.get('/tasks?' + p), api.get('/projects')]);

-  const handleSaveTask = async (form) => {

-      else { await api.post('/tasks', form); toast.success('Task added'); }

+      else              { await api.post('/tasks', form);               toast.success('Task added');   }

-      await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');

-    } catch (e) { toast.error(e.message); }

+    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');

-    setSelected(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });

+  const toggleSelect = (id) => setSelected(s => {

+    const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n;

-    toast.success(`${selected.size} task${selected.size > 1 ? 's' : ''} marked done`);

+    toast.success(`${selected.size} tasks done`);

const hasFilters = statusFilter || catFilter || priorityFilter;

+  const KANBAN_COLS = ['Open', 'In Progress', 'Waiting', 'Done'];

+  const byStatus = KANBAN_COLS.reduce((acc, s) => {

+    acc[s] = tasks.filter(t => t.status === s);

-    <div className="max-w-2xl mx-auto px-4 py-6">

-        <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5">

+    <div className="flex flex-col h-full overflow-hidden">

-      <div className="flex gap-2 mb-3">

-        <div className="relative flex-1">

-          <Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />

-            placeholder="Search tasks…"

-            onChange={e => setSearch(e.target.value)}

+      <div className="shrink-0 px-4 pt-4 pb-3 bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800">

+        <div className="flex items-center justify-between mb-3">

+          <div className="flex items-center gap-2">

+            <div className="flex bg-gray-100 dark:bg-gray-800 rounded-xl p-0.5 gap-0.5">

+              {[{ id:'grid', label:'Grid' }, { id:'kanban', label:'Board' }].map(v => (

+                <button key={v.id} onClick={() => setViewMode(v.id)}

+                  className={`px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${

+                    viewMode === v.id ? 'bg-white dark:bg-gray-700 text-gray-900 dark:text-white shadow-sm' : 'text-gray-500'

+            <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5 py-2">

+              <Plus size={14} /> New Task

-          onClick={() => setShowFilters(!showFilters)}

-          className={`btn-secondary flex items-center gap-1.5 shrink-0 ${hasFilters ? 'bg-primary/10 text-primary border-primary/30' : ''}`}

-          {hasFilters ? 'Filtered' : 'Filter'}

-        <div className="card mb-3 grid grid-cols-3 gap-3">

-            <label className="block text-xs font-medium text-gray-500 mb-1">Status</label>

-            <select className="select text-xs py-1.5" value={statusFilter} onChange={e => setStatusFilter(e.target.value)}>

-              <option value="">All</option>

+        <div className="flex gap-2 flex-wrap">

+          <div className="relative flex-1 min-w-[180px]">

+            <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />

+            <input className="input pl-8 py-2 text-sm" placeholder="Search tasks…" value={search} onChange={e => setSearch(e.target.value)} />

+          <button onClick={() => setShowFilters(!showFilters)}

+            className={`btn-secondary flex items-center gap-1.5 py-2 text-sm ${hasFilters ? 'border-primary text-primary' : ''}`}>

+            <SlidersHorizontal size={13} />

+            {hasFilters ? 'Filtered' : 'Filter'}

+          <div className="flex gap-2 mt-2 flex-wrap">

+            <select className="select text-xs py-1.5 w-auto" value={statusFilter} onChange={e => setStatus(e.target.value)}>

+              <option value="">All Status</option>

{STATUSES.map(s => <option key={s}>{s}</option>)}

-            <label className="block text-xs font-medium text-gray-500 mb-1">Category</label>

-            <select className="select text-xs py-1.5" value={catFilter} onChange={e => setCatFilter(e.target.value)}>

+            <select className="select text-xs py-1.5 w-auto" value={catFilter} onChange={e => setCat(e.target.value)}>

+              <option value="">All Categories</option>

-            <label className="block text-xs font-medium text-gray-500 mb-1">Priority</label>

-            <select className="select text-xs py-1.5" value={priorityFilter} onChange={e => setPriorityFilter(e.target.value)}>

-              <option value="">All</option>

+            <select className="select text-xs py-1.5 w-auto" value={priorityFilter} onChange={e => setPri(e.target.value)}>

+              <option value="">All Priorities</option>

{PRIORITIES.map(p => <option key={p}>{p}</option>)}

-            <div className="col-span-3 flex justify-end">

-              <button onClick={() => { setStatusFilter(''); setCatFilter(''); setPriorityFilter(''); }} className="text-xs text-primary hover:underline">

+              <button onClick={() => { setStatus(''); setCat(''); setPri(''); }}

+                className="flex items-center gap-1 text-xs text-primary hover:underline px-2">

-        <div className="flex items-center gap-3 mb-3 px-4 py-2.5 bg-primary/10 dark:bg-primary/20 rounded-lg border border-primary/20">

-          <button onClick={bulkDone} className="btn-primary py-1 text-xs flex items-center gap-1">

-            <CheckSquare size={12} /> Mark done

-          <button onClick={() => setSelected(new Set())} className="btn-ghost text-xs">Clear</button>

+          <div className="flex items-center gap-3 mt-2 px-3 py-2 bg-primary/10 rounded-xl border border-primary/20">

+            <button onClick={bulkDone} className="btn-primary py-1 text-xs flex items-center gap-1">

+              <CheckSquare size={11} /> Mark done

+            <button onClick={() => setSelected(new Set())} className="btn-ghost text-xs">Clear</button>

-          {[...Array(5)].map((_, i) => <div key={i} className="skeleton h-24 rounded-lg" />)}

+        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 p-4 overflow-y-auto flex-1">

+          {[...Array(8)].map((_, i) => <div key={i} className="skeleton h-32 rounded-xl" />)}

-        <div className="text-center py-16">

-          <CheckSquare size={36} className="text-gray-300 dark:text-gray-700 mx-auto mb-3" />

-          {search && <button onClick={() => setSearch('')} className="btn-ghost mt-2 text-sm">Clear search</button>}

+        <div className="flex-1 flex flex-col items-center justify-center gap-3 p-8">

+          <CheckSquare size={40} className="text-gray-200 dark:text-gray-700" />

+            <button onClick={() => { setSearch(''); setStatus(''); setCat(''); setPri(''); }} className="btn-secondary text-sm">

+        /* ── GRID view ─────────────────────────────────── */

+        <div className="flex-1 overflow-y-auto p-4">

+
{tasks.length} task{tasks.length !== 1 ? 's' : ''}

+          <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">

+              <div key={task.id} className="relative">

+                <input type="checkbox" className="absolute top-3 left-3 z-10 w-3.5 h-3.5 accent-primary cursor-pointer rounded"

+                  checked={selected.has(task.id)} onChange={() => toggleSelect(task.id)} />

+                  <TaskCard task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

-
{tasks.length} task{tasks.length !== 1 ? 's' : ''}

-            <div key={task.id} className="relative">

-                className="absolute left-3 top-1/2 -translate-y-1/2 z-10 w-4 h-4 accent-primary cursor-pointer"

-                checked={selected.has(task.id)}

-                onChange={() => toggleSelect(task.id)}

-                <TaskCard task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

+        /* ── KANBAN / BOARD view ────────────────────────── */

+        <div className="flex gap-3 p-4 overflow-x-auto flex-1 min-h-0"

+          style={{ scrollSnapType: 'x mandatory', WebkitOverflowScrolling: 'touch' }}>

+            const col = STATUS_COLS.find(c => c.id === status);

+            const colTasks = byStatus[status] || [];

+              <div key={status} className="shrink-0 flex flex-col rounded-2xl bg-[#F7F7FB] dark:bg-gray-800/40 min-h-0"

+                style={{ width: 'calc(100vw - 64px)', maxWidth: 270, scrollSnapAlign: 'start' }}>

+                <div className="flex items-center justify-between px-3 pt-3 pb-2">

+                  <div className="flex items-center gap-2">

+                    <span className={`badge text-[10px] py-0.5 ${col?.color}`}>{colTasks.length}

+                  <button onClick={() => setShowNew(true)}

+                    className="w-6 h-6 rounded-lg bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-600 flex items-center justify-center text-gray-400 hover:text-primary hover:border-primary transition-all">

+                <div className="flex-1 overflow-y-auto px-3 pb-3 space-y-2.5 min-h-[40px]">

+                  {colTasks.map(task => (

+                    <TaskCard key={task.id} task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

+                  {colTasks.length === 0 && (

+                    <div className="border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-xl h-16 flex items-center justify-center">

-        <TaskModal task={editTask} projects={projects} onSave={handleSaveTask} onClose={() => { setShowNew(false); setEditTask(null); }} />

+        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />

import { useState, useEffect, useRef } from 'react';
import { Plus, Search, Filter, CheckSquare } from 'lucide-react';
import toast from 'react-hot-toast';
import api from '../api';
import TaskCard from './TaskCard';
import TaskModal from './TaskModal';
import ConfirmDialog from './ConfirmDialog';
import { CATEGORIES, STATUSES, PRIORITIES, getCategoryClass, getPriorityClass } from '../utils';

const SORT_OPTIONS = [
  { value: 'priority', label: 'Priority' },
  { value: 'due_date', label: 'Due Date' },
  { value: 'created_at', label: 'Created' },
];

function useDebounce(value, delay = 300) {
  const [dv, setDv] = useState(value);
  useEffect(() => { const t = setTimeout(() => setDv(value), delay); return () => clearTimeout(t); }, [value, delay]);
  return dv;
}

export default function Tasks() {
  const [tasks, setTasks] = useState([]);
  const [projects, setProjects] = useState([]);
  const [loading, setLoading] = useState(true);
  const [search, setSearch] = useState('');
  const [statusFilter, setStatusFilter] = useState('');
  const [catFilter, setCatFilter] = useState('');
  const [priorityFilter, setPriorityFilter] = useState('');
  const [editTask, setEditTask] = useState(null);
  const [deleteTask, setDeleteTask] = useState(null);
  const [showNew, setShowNew] = useState(false);
  const [selected, setSelected] = useState(new Set());
  const [showFilters, setShowFilters] = useState(false);
  const debouncedSearch = useDebounce(search);

  const load = async () => {
    setLoading(true);
    const params = new URLSearchParams();
    if (debouncedSearch) params.set('search', debouncedSearch);
    if (statusFilter) params.set('status', statusFilter);
    if (catFilter) params.set('category', catFilter);
    if (priorityFilter) params.set('priority', priorityFilter);
    try {
      const [t, pr] = await Promise.all([api.get('/tasks?' + params), api.get('/projects')]);
      setTasks(t);
      setProjects(pr);
    } finally { setLoading(false); }
  };

  useEffect(() => { load(); }, [debouncedSearch, statusFilter, catFilter, priorityFilter]);

  const handleSaveTask = async (form) => {
    try {
      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
      else { await api.post('/tasks', form); toast.success('Task added'); }
      setEditTask(null); setShowNew(false); load();
    } catch (e) { toast.error(e.message); }
  };

  const handleDelete = async () => {
    try {
      await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');
      setDeleteTask(null); load();
    } catch (e) { toast.error(e.message); }
  };

  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };

  const toggleSelect = (id) => {
    setSelected(s => { const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n; });
  };

  const bulkDone = async () => {
    await Promise.all([...selected].map(id => api.patch(`/tasks/${id}/status`, { status: 'Done' })));
    toast.success(`${selected.size} task${selected.size > 1 ? 's' : ''} marked done`);
    setSelected(new Set()); load();
  };

  const hasFilters = statusFilter || catFilter || priorityFilter;

  return (

Tasks

        <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5">
          <Plus size={15} /> New Task
        </button>

      {/* Search + filter bar */}

          <Search size={14} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
          <input
            className="input pl-8"
            placeholder="Search tasks…"
            value={search}
            onChange={e => setSearch(e.target.value)}
          />

        <button
          onClick={() => setShowFilters(!showFilters)}
          className={`btn-secondary flex items-center gap-1.5 shrink-0 ${hasFilters ? 'bg-primary/10 text-primary border-primary/30' : ''}`}
        >
          <Filter size={14} />
          {hasFilters ? 'Filtered' : 'Filter'}
        </button>

      {/* Filters */}
      {showFilters && (

            Status
            <select className="select text-xs py-1.5" value={statusFilter} onChange={e => setStatusFilter(e.target.value)}>
              <option value="">All</option>
              {STATUSES.map(s => <option key={s}>{s}</option>)}
            </select>

            Category
            <select className="select text-xs py-1.5" value={catFilter} onChange={e => setCatFilter(e.target.value)}>
              <option value="">All</option>
              {Object.entries(CATEGORIES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
            </select>

            Priority
            <select className="select text-xs py-1.5" value={priorityFilter} onChange={e => setPriorityFilter(e.target.value)}>
              <option value="">All</option>
              {PRIORITIES.map(p => <option key={p}>{p}</option>)}
            </select>

          {hasFilters && (

              <button onClick={() => { setStatusFilter(''); setCatFilter(''); setPriorityFilter(''); }} className="text-xs text-primary hover:underline">
                Clear filters
              </button>

          )}

      )}

      {/* Bulk actions */}
      {selected.size > 0 && (

          {selected.size} selected
          <button onClick={bulkDone} className="btn-primary py-1 text-xs flex items-center gap-1">
            <CheckSquare size={12} /> Mark done
          </button>
          <button onClick={() => setSelected(new Set())} className="btn-ghost text-xs">Clear</button>

      )}

      {/* Tasks */}
      {loading ? (

          {[...Array(5)].map((_, i) =>
)}

      ) : tasks.length === 0 ? (

          <CheckSquare size={36} className="text-gray-300 dark:text-gray-700 mx-auto mb-3" />

No tasks found

          {search && <button onClick={() => setSearch('')} className="btn-ghost mt-2 text-sm">Clear search</button>}

      ) : (

{tasks.length} task{tasks.length !== 1 ? 's' : ''}

          {tasks.map(task => (

              <input
                type="checkbox"
                className="absolute left-3 top-1/2 -translate-y-1/2 z-10 w-4 h-4 accent-primary cursor-pointer"
                checked={selected.has(task.id)}
                onChange={() => toggleSelect(task.id)}
              />

                <TaskCard task={task} onEdit={setEditTask} onDelete={setDeleteTask} onToggleFocus={toggleFocus} />

          ))}

      )}

      {(showNew || editTask) && (
        <TaskModal task={editTask} projects={projects} onSave={handleSaveTask} onClose={() => { setShowNew(false); setEditTask(null); }} />
      )}
      {deleteTask && (
        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
      )}

  );
}


import { useState, useEffect } from 'react';
import { Plus, FileText, Trash2, Pencil, Calendar, FolderKanban } from 'lucide-react';
import toast from 'react-hot-toast';
import api from '../api';
import ConfirmDialog from './ConfirmDialog';
import { formatDate } from '../utils';

const NOTE_COLORS = [
  'bg-violet-50 dark:bg-violet-900/20 border-violet-200 dark:border-violet-800',
  'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800',
  'bg-amber-50 dark:bg-amber-900/20 border-amber-200 dark:border-amber-800',
  'bg-teal-50 dark:bg-teal-900/20 border-teal-200 dark:border-teal-800',
  'bg-pink-50 dark:bg-pink-900/20 border-pink-200 dark:border-pink-800',
  'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800',
];

function NoteModal({ note, projects, onSave, onClose }) {
  const [form, setForm] = useState({
    title: '', body: '', project_id: null,
    date: new Date().toISOString().split('T')[0], ...note,
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  return (

 e.stopPropagation()}>

{note?.id ? 'Edit Note' : 'New Note'}

        <form onSubmit={e => { e.preventDefault(); onSave(form); }} className="px-5 py-4 space-y-3">
          <input className="input font-medium" required placeholder="Title" value={form.title} onChange={e => set('title', e.target.value)} autoFocus />
          <textarea className="input resize-none" rows={7} placeholder="Write your note…" value={form.body} onChange={e => set('body', e.target.value)} />

              Date
              <input type="date" className="input" value={form.date} onChange={e => set('date', e.target.value)} />

              Project
              <select className="select" value={form.project_id || ''} onChange={e => set('project_id', e.target.value || null)}>
                <option value="">No project</option>
                {projects.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
              </select>

            <button type="button" onClick={onClose} className="btn-secondary">Cancel</button>
            <button type="submit" className="btn-primary">{note?.id ? 'Save' : 'Add Note'}</button>

        </form>

  );
}

function NoteCard({ note, colorClass, onEdit, onDelete }) {
  const [expanded, setExpanded] = useState(false);
  return (
    <div className={`rounded-2xl border p-4 flex flex-col gap-2 group transition-all duration-200 hover:shadow-hover hover:-translate-y-0.5 ${colorClass}`}>

{note.title}

          <button onClick={() => onEdit(note)} className="p-1.5 rounded-lg hover:bg-white/60 dark:hover:bg-gray-700 text-gray-500 transition-colors">
            <Pencil size={12} />
          </button>
          <button onClick={() => onDelete(note)} className="p-1.5 rounded-lg hover:bg-red-100 dark:hover:bg-red-900/30 text-gray-400 hover:text-red-500 transition-colors">
            <Trash2 size={12} />
          </button>

      {note.body && (
        <p className={`text-xs text-gray-600 dark:text-gray-400 leading-relaxed whitespace-pre-wrap ${!expanded ? 'line-clamp-4' : ''}`}>
          {note.body}

      )}
      {note.body && note.body.length > 200 && (
        <button onClick={() => setExpanded(!expanded)} className="text-[10px] font-medium text-primary hover:underline self-start">
          {expanded ? 'Show less' : 'Read more'}
        </button>
      )}

        <Calendar size={10} className="text-gray-400 shrink-0" />
        {formatDate(note.date)}
        {note.project_name && (

            <FolderKanban size={9} />{note.project_name}

        )}

  );
}

export default function Notes() {
  const [notes, setNotes]       = useState([]);
  const [projects, setProjects] = useState([]);
  const [loading, setLoading]   = useState(true);
  const [editNote, setEditNote] = useState(null);
  const [deleteNote, setDeleteNote] = useState(null);
  const [showNew, setShowNew]   = useState(false);

  const load = async () => {
    setLoading(true);
    try {
      const [n, pr] = await Promise.all([api.get('/notes'), api.get('/projects')]);
      setNotes(n); setProjects(pr);
    } finally { setLoading(false); }
  };
  useEffect(() => { load(); }, []);

  const handleSave = async (form) => {
    try {
      if (form.id) { await api.put(`/notes/${form.id}`, form); toast.success('Note updated'); }
      else         { await api.post('/notes', form);            toast.success('Note added');   }
      setEditNote(null); setShowNew(false); load();
    } catch (e) { toast.error(e.message); }
  };

  const handleDelete = async () => {
    await api.delete(`/notes/${deleteNote.id}`); toast.success('Note deleted');
    setDeleteNote(null); load();
  };

  return (

      {/* Header */}

Notes

          {!loading &&
{notes.length} note{notes.length !== 1 ? 's' : ''}
}

        <button onClick={() => setShowNew(true)} className="btn-primary flex items-center gap-1.5">
          <Plus size={14} /> New Note
        </button>

      {/* Grid */}

        {loading ? (

            {[...Array(6)].map((_, i) =>
)}

        ) : notes.length === 0 ? (

            <FileText size={44} className="text-gray-200 dark:text-gray-700" />

No notes yet

Capture ideas, meeting notes, decisions

            <button onClick={() => setShowNew(true)} className="btn-primary">Create your first note</button>

        ) : (
          /* Masonry-style columns */

            {notes.map((note, i) => (

                <NoteCard
                  note={note}
                  colorClass={NOTE_COLORS[i % NOTE_COLORS.length]}
                  onEdit={setEditNote}
                  onDelete={setDeleteNote}
                />

            ))}

        )}

      {(showNew || editNote) && (
        <NoteModal note={editNote} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditNote(null); }} />
      )}
      {deleteNote && (
        <ConfirmDialog title="Delete note?" message={`"${deleteNote.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteNote(null)} />
      )}

  );
}