fix all the issues in all terminals its showing yellow


## plugin:context7:context7
Use this server to fetch current documentation whenever the user asks about a library, framework, SDK, API, CLI tool, or cloud service -- even well-known ones like React, Next.js, Prisma, Express, Tailwind, Django, or Spring Boot. This includes API syntax, configuration, version migration, library-specific debugging, setup instructions, and CLI tool usage. Use even when you think you know the answer -- your training data may not reflect recent changes. Prefer this over web search for library docs.

Do not use for: refactoring, writing scripts from scratch, debugging business logic, code review, or general programming concepts.


Let me check the workspace to understand what's running and what warnings are showing.


Bash

List workspace files


client
data
dist
node_modules
package-lock.json
package.json
README.md
server


npm start 2>&1 | head -50 &
sleep 3 && kill %1 2>/dev/null; true

Capture startup warnings from server


cd /Users/khalidbinkalban/my-workspace/client && npm start 2>&1 | head -80 &
sleep 5 && kill %1 2>/dev/null; true

Capture startup warnings from client


The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.

Note: The user's next message may contain a correction or preference. Pay close attention — if they explain what went wrong or how they'd prefer you to work, consider saving that to memory for future sessions.


[Request interrupted by user for tool use]


again


Let me read the source files to find the warnings.


server/routes/tasks.js
server/routes/notes.js
server/routes/search.js
server/routes/weekly.js
server/routes/projects.js
server/routes/people.js
server/db.js
server/routes/ai.js
server/index.js


1	{
2	  "name": "my-workspace",
3	  "version": "1.0.0",
4	  "description": "Senior Manager Personal Workspace — DEWA",
5	  "scripts": {
6	    "dev": "concurrently \"npm run server\" \"npm run client\"",
7	    "server": "nodemon server/index.js",
8	    "client": "vite client",
9	    "build": "vite build client",
10	    "start": "node server/index.js"
11	  },
12	  "dependencies": {
13	    "@anthropic-ai/sdk": "^0.37.0",
14	    "@dnd-kit/core": "^6.3.1",
15	    "@dnd-kit/utilities": "^3.2.2",
16	    "better-sqlite3": "^11.7.0",
17	    "cors": "^2.8.5",
18	    "dotenv": "^16.4.7",
19	    "express": "^4.21.2",
20	    "lucide-react": "^0.469.0",
21	    "react": "^18.3.1",
22	    "react-dom": "^18.3.1",
23	    "react-hot-toast": "^2.4.1",
24	    "react-router-dom": "^6.28.0"
25	  },
26	  "devDependencies": {
27	    "@vitejs/plugin-react": "^4.3.1",
28	    "autoprefixer": "^10.4.20",
29	    "concurrently": "^9.1.2",
30	    "nodemon": "^3.1.9",
31	    "postcss": "^8.5.1",
32	    "tailwindcss": "^3.4.17",
33	    "vite": "^6.0.6"
34	  }
35	}
36

my-workspace

concurrently "npm run server" "npm run client"


client/src/main.jsx
client/src/api.js
client/src/utils.js
client/src/components/ConfirmDialog.jsx
client/src/components/TaskModal.jsx
client/src/components/Search.jsx
client/src/components/TaskCard.jsx
client/src/components/RightPanel.jsx
client/src/components/Notes.jsx
client/src/components/FollowUps.jsx
client/src/components/WeeklyReview.jsx
client/src/components/BottomNav.jsx
client/src/App.jsx
client/src/components/Projects.jsx
client/src/components/People.jsx
client/src/components/Sidebar.jsx
client/src/components/Today.jsx
client/src/components/Tasks.jsx
client/src/components/ProjectDetail.jsx
client/src/components/History.jsx
client/src/components/Inbox.jsx


1	const path = require('path');
2	require('dotenv').config({ path: path.join(__dirname, '../.env') });
3	const express = require('express');
4	const cors = require('cors');
5
6	// Initialize DB (runs migrations + seed)
7	require('./db');
8
9	const app = express();
10	app.use(cors());
11	app.use(express.json({ limit: '10mb' }));
12
13	// Routes
14	app.use('/api/projects', require('./routes/projects'));
15	app.use('/api/tasks', require('./routes/tasks'));
16	app.use('/api/notes', require('./routes/notes'));
17	app.use('/api/ai', require('./routes/ai'));
18	app.use('/api/people', require('./routes/people'));
19	app.use('/api/search', require('./routes/search'));
20	app.use('/api/weekly-review', require('./routes/weekly'));
21
22	// Serve static build in production
23	if (process.env.NODE_ENV === 'production') {
24	  app.use(express.static(path.join(__dirname, '../dist')));
25	  app.get('*', (req, res) => {
26	    res.sendFile(path.join(__dirname, '../dist/index.html'));
27	  });
28	}
29
30	const PORT = process.env.PORT || 3001;
31	app.listen(PORT, () => {
32	  console.log(`🚀 Server running on http://localhost:${PORT}`);
33	});
34

const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '../.env') });
const express = require('express');
const cors = require('cors');

// Initialize DB (runs migrations + seed)
require('./db');

const app = express();
app.use(cors());
app.use(express.json({ limit: '10mb' }));

// Routes
app.use('/api/projects', require('./routes/projects'));
app.use('/api/tasks', require('./routes/tasks'));
app.use('/api/notes', require('./routes/notes'));
app.use('/api/ai', require('./routes/ai'));
app.use('/api/people', require('./routes/people'));
app.use('/api/search', require('./routes/search'));
app.use('/api/weekly-review', require('./routes/weekly'));

// Serve static build in production
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../dist')));
  app.get('*', (req, res) => {
    res.sendFile(path.join(__dirname, '../dist/index.html'));
  });
}

const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
  console.log(`🚀 Server running on http://localhost:${PORT}`);
});


1	import { useState, useEffect, createContext, useContext } from 'react';
2	import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
3	import Sidebar from './components/Sidebar';
4	import BottomNav from './components/BottomNav';
5	import RightPanel from './components/RightPanel';
6	import Search from './components/Search';
7	import Today from './components/Today';
8	import Inbox from './components/Inbox';
9	import Projects from './components/Projects';
10	import ProjectDetail from './components/ProjectDetail';
11	import Tasks from './components/Tasks';
12	import Notes from './components/Notes';
13	import FollowUps from './components/FollowUps';
14	import People from './components/People';
15	import WeeklyReview from './components/WeeklyReview';
16	import History from './components/History';
17	import { Toaster } from 'react-hot-toast';
18
19	export const AppContext = createContext({});
20	export const useApp = () => useContext(AppContext);
21
22	// Pages that show the right panel
23	const RIGHT_PANEL_ROUTES = ['/today', '/'];
24
25	export default function App() {
26	  const [darkMode, setDarkMode] = useState(() => localStorage.getItem('darkMode') === 'true');
27	  const [searchOpen, setSearchOpen] = useState(false);
28
29	  useEffect(() => {
30	    document.documentElement.classList.toggle('dark', darkMode);
31	    localStorage.setItem('darkMode', darkMode);
32	  }, [darkMode]);
33
34	  useEffect(() => {
35	    const onKey = (e) => {
36	      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setSearchOpen(true); }
37	      if (e.key === 'Escape') setSearchOpen(false);
38	    };
39	    window.addEventListener('keydown', onKey);
40	    return () => window.removeEventListener('keydown', onKey);
41	  }, []);
42
43	  return (
44	    <AppContext.Provider value={{ darkMode, setDarkMode, setSearchOpen }}>
45	      <BrowserRouter>
46	        <div className="flex h-screen overflow-hidden bg-[#F0F2F5] dark:bg-gray-950">
47	          {/* Left sidebar */}
48	          <Sidebar onSearchOpen={() => setSearchOpen(true)} />
49
50	          {/* Main content */}
51	          <main className="flex-1 overflow-y-auto pb-20 md:pb-0 min-w-0">
52	            <Routes>
53	              <Route path="/"               element={<Navigate to="/today" replace />} />
54	              <Route path="/today"          element={<Today />} />
55	              <Route path="/inbox"          element={<Inbox />} />
56	              <Route path="/projects"       element={<Projects />} />
57	              <Route path="/projects/:id"   element={<ProjectDetail />} />
58	              <Route path="/tasks"          element={<Tasks />} />
59	              <Route path="/notes"          element={<Notes />} />
60	              <Route path="/follow-ups"     element={<FollowUps />} />
61	              <Route path="/people"         element={<People />} />
62	              <Route path="/weekly-review"  element={<WeeklyReview />} />
63	              <Route path="/history"        element={<History />} />
64	            </Routes>
65	          </main>
66
67	          {/* Right executive panel (Today only, desktop XL) */}
68	          <Routes>
69	            <Route path="/"      element={<RightPanel />} />
70	            <Route path="/today" element={<RightPanel />} />
71	          </Routes>
72
73	          {/* Mobile bottom nav */}
74	          <BottomNav />
75
76	          {/* Search overlay */}
77	          {searchOpen && <Search onClose={() => setSearchOpen(false)} />}
78	        </div>
79
80	        <Toaster
81	          position="top-right"
82	          toastOptions={{
83	            duration: 3000,
84	            style: { borderRadius: '12px', fontSize: '13px', fontFamily: 'Inter, sans-serif' },
85	          }}
86	        />
87	      </BrowserRouter>
88	    </AppContext.Provider>
89	  );
90	}
91

import { useState, useEffect, createContext, useContext } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import Sidebar from './components/Sidebar';
import BottomNav from './components/BottomNav';
import RightPanel from './components/RightPanel';
import Search from './components/Search';
import Today from './components/Today';
import Inbox from './components/Inbox';
import Projects from './components/Projects';
import ProjectDetail from './components/ProjectDetail';
import Tasks from './components/Tasks';
import Notes from './components/Notes';
import FollowUps from './components/FollowUps';
import People from './components/People';
import WeeklyReview from './components/WeeklyReview';
import History from './components/History';
import { Toaster } from 'react-hot-toast';

export const AppContext = createContext({});
export const useApp = () => useContext(AppContext);

// Pages that show the right panel
const RIGHT_PANEL_ROUTES = ['/today', '/'];

export default function App() {
  const [darkMode, setDarkMode] = useState(() => localStorage.getItem('darkMode') === 'true');
  const [searchOpen, setSearchOpen] = useState(false);

  useEffect(() => {
    document.documentElement.classList.toggle('dark', darkMode);
    localStorage.setItem('darkMode', darkMode);
  }, [darkMode]);

  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setSearchOpen(true); }
      if (e.key === 'Escape') setSearchOpen(false);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, []);

  return (
    <AppContext.Provider value={{ darkMode, setDarkMode, setSearchOpen }}>
      <BrowserRouter>
        <div className="flex h-screen overflow-hidden bg-[#F0F2F5] dark:bg-gray-950">
          {/* Left sidebar */}
          <Sidebar onSearchOpen={() => setSearchOpen(true)} />

          {/* Main content */}
          <main className="flex-1 overflow-y-auto pb-20 md:pb-0 min-w-0">
            <Routes>
              <Route path="/"               element={<Navigate to="/today" replace />} />
              <Route path="/today"          element={<Today />} />
              <Route path="/inbox"          element={<Inbox />} />
              <Route path="/projects"       element={<Projects />} />
              <Route path="/projects/:id"   element={<ProjectDetail />} />
              <Route path="/tasks"          element={<Tasks />} />
              <Route path="/notes"          element={<Notes />} />
              <Route path="/follow-ups"     element={<FollowUps />} />
              <Route path="/people"         element={<People />} />
              <Route path="/weekly-review"  element={<WeeklyReview />} />
              <Route path="/history"        element={<History />} />
            </Routes>
          </main>

          {/* Right executive panel (Today only, desktop XL) */}
          <Routes>
            <Route path="/"      element={<RightPanel />} />
            <Route path="/today" element={<RightPanel />} />
          </Routes>

          {/* Mobile bottom nav */}
          <BottomNav />

          {/* Search overlay */}
          {searchOpen && <Search onClose={() => setSearchOpen(false)} />}
        </div>

        <Toaster
          position="top-right"
          toastOptions={{
            duration: 3000,
            style: { borderRadius: '12px', fontSize: '13px', fontFamily: 'Inter, sans-serif' },
          }}
        />
      </BrowserRouter>
    </AppContext.Provider>
  );
}


1	const Database = require('better-sqlite3');
2	const path = require('path');
3	const fs = require('fs');
4
5	const DB_PATH = path.join(__dirname, '../data/workspace.db');
6	const dataDir = path.dirname(DB_PATH);
7	if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });
8
9	const db = new Database(DB_PATH);
10	db.pragma('journal_mode = WAL');
11	db.pragma('foreign_keys = ON');
12
13	// Migrate people table — add columns if not present
14	;['pr_number','grade','designation','department','section','reporting_line','mobile_number','place'].forEach(col => {
15	  try { db.exec(`ALTER TABLE people ADD COLUMN ${col} TEXT DEFAULT ''`); } catch {}
16	});
17
18	function initDb() {
19	  db.exec(`
20	    CREATE TABLE IF NOT EXISTS projects (
21	      id INTEGER PRIMARY KEY AUTOINCREMENT,
22	      name TEXT NOT NULL,
23	      category TEXT NOT NULL DEFAULT 'adhoc',
24	      status TEXT NOT NULL DEFAULT 'Open',
25	      priority TEXT NOT NULL DEFAULT 'Medium',
26	      description TEXT DEFAULT '',
27	      last_update TEXT DEFAULT '',
28	      next_step TEXT DEFAULT '',
29	      created_at TEXT DEFAULT (datetime('now')),
30	      updated_at TEXT DEFAULT (datetime('now'))
31	    );
32
33	    CREATE TABLE IF NOT EXISTS tasks (
34	      id INTEGER PRIMARY KEY AUTOINCREMENT,
35	      title TEXT NOT NULL,
36	      notes TEXT DEFAULT '',
37	      project_id INTEGER REFERENCES projects(id) ON DELETE SET NULL,
38	      category TEXT NOT NULL DEFAULT 'adhoc',
39	      priority TEXT NOT NULL DEFAULT 'Medium',
40	      status TEXT NOT NULL DEFAULT 'Open',
41	      assignee TEXT DEFAULT '',
42	      due_date TEXT DEFAULT '',
43	      is_follow_up INTEGER DEFAULT 0,
44	      is_today_focus INTEGER DEFAULT 0,
45	      completed_at TEXT DEFAULT '',
46	      created_at TEXT DEFAULT (datetime('now')),
47	      updated_at TEXT DEFAULT (datetime('now'))
48	    );
49
50	    CREATE TABLE IF NOT EXISTS notes (
51	      id INTEGER PRIMARY KEY AUTOINCREMENT,
52	      title TEXT NOT NULL,
53	      body TEXT DEFAULT '',
54	      project_id INTEGER REFERENCES projects(id) ON DELETE SET NULL,
55	      date TEXT DEFAULT (date('now')),
56	      created_at TEXT DEFAULT (datetime('now'))
57	    );
58
59	    CREATE TABLE IF NOT EXISTS people (
60	      id INTEGER PRIMARY KEY AUTOINCREMENT,
61	      name TEXT NOT NULL UNIQUE,
62	      role TEXT DEFAULT '',
63	      created_at TEXT DEFAULT (datetime('now'))
64	    );
65
66	    CREATE TABLE IF NOT EXISTS settings (
67	      key TEXT PRIMARY KEY,
68	      value TEXT
69	    );
70
71	    CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
72	    CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id);
73	    CREATE INDEX IF NOT EXISTS idx_tasks_today ON tasks(is_today_focus);
74	    CREATE INDEX IF NOT EXISTS idx_tasks_followup ON tasks(is_follow_up);
75	    CREATE INDEX IF NOT EXISTS idx_projects_category ON projects(category);
76	    CREATE INDEX IF NOT EXISTS idx_notes_date ON notes(date);
77	  `);
78
79	  const seeded = db.prepare("SELECT value FROM settings WHERE key = 'seeded'").get();
80	  if (!seeded) {
81	    seedData();
82	    db.prepare("INSERT INTO settings (key, value) VALUES ('seeded', 'true')").run();
83	    console.log('✅ Database seeded with initial data');
84	  }
85	}
86
87	function seedData() {
88	  const insertProject = db.prepare(`
89	    INSERT INTO projects (name, category, status, priority) VALUES (?, ?, ?, ?)
90	  `);
91
92	  const projects = [
93	    // AI Adoption & Strategy
94	    ['Microsoft Copilot Rollout', 'ai', 'In Progress', 'High'],
95	    ['DEWA AI Academy', 'ai', 'In Progress', 'High'],
96	    ['AI Command Center RFP', 'ai', 'Open', 'High'],
97	    ['AI Champions Program', 'ai', 'In Progress', 'High'],
98	    ['AI OS Initiative', 'ai', 'In Progress', 'Urgent'],
99	    ['COE End-to-End', 'ai', 'In Progress', 'High'],
100	    ['GitHub Copilot Plan', 'ai', 'Open', 'High'],
101	    ['WalkMe & SAP Joule', 'ai', 'In Progress', 'Medium'],
102	    ['Rummana at Work', 'ai', 'Open', 'Medium'],
103	    ['Blink App AI Adoption', 'ai', 'Open', 'Medium'],
104	    // Vendor & Partnerships
105	    ['Google Partnership & NDA', 'vendor', 'Waiting', 'Urgent'],
106	    ['Polynome Engagement', 'vendor', 'In Progress', 'High'],
107	    ['Genspark Engagement', 'vendor', 'Waiting', 'Medium'],
108	    ['IMD Proposal', 'vendor', 'Open', 'Medium'],
109	    ['Ducont Wave 2', 'vendor', 'In Progress', 'High'],
110	    ['ElevenLabs Engagement', 'vendor', 'Open', 'Medium'],
111	    ['Dell Engagement', 'vendor', 'Open', 'Medium'],
112	    ['Coursera / Udemy Licenses', 'vendor', 'In Progress', 'Medium'],
113	    // Governance & Reporting
114	    ['I&TF Quarterly Report', 'gov', 'In Progress', 'Urgent'],
115	    ['AI Charter & ISO 42001', 'gov', 'Open', 'High'],
116	    ['KPIs & Blueprint', 'gov', 'In Progress', 'High'],
117	    ['IETF Benchmark', 'gov', 'In Progress', 'High'],
118	    // People & Team
119	    ['Employees Rating', 'people', 'Open', 'High'],
120	    ['Data Champions Program', 'people', 'Open', 'Medium'],
121	    ['Outsource Assessment', 'people', 'In Progress', 'Medium'],
122	    ['AI Ambassadors Survey', 'people', 'In Progress', 'High'],
123	    // Events & External
124	    ['WEF Lighthouse', 'events', 'Open', 'High'],
125	    ['Gartner Data Summit', 'events', 'Open', 'Medium'],
126	    ['GenAI Week Emirates Towers', 'events', 'Open', 'Medium'],
127	    ['Microsoft Community Conference', 'events', 'Open', 'Medium'],
128	    // Strategic Initiatives
129	    ['AlHasbah Use Cases Phase I', 'strategic', 'In Progress', 'High'],
130	    ['Digital DEWA Direction', 'strategic', 'Open', 'High'],
131	    ['D2D Workshop', 'strategic', 'In Progress', 'High'],
132	    ['AICC ROI Tracking', 'strategic', 'Open', 'High'],
133	    // CAIO / EVP Ad Hoc
134	    ['EVP MD Finance Agent', 'adhoc', 'Open', 'Urgent'],
135	    ['CAIO AI OS Initiative', 'adhoc', 'In Progress', 'High'],
136	  ];
137
138	  const seedProjects = db.transaction(() => {
139	    for (const p of projects) insertProject.run(...p);
140	  });
141	  seedProjects();
142
143	  const insertTask = db.prepare(`
144	    INSERT INTO tasks (title, category, priority, assignee, due_date, is_follow_up, status)
145	    VALUES (?, ?, ?, ?, ?, ?, 'Open')
146	  `);
147
148	  const tasks = [
149	    ['Google NDA: meet Legal Affairs + Hadi + CAIO', 'vendor', 'Urgent', 'Hadi', '', 1],
150	    ['Chandini to provide process map of features announcement', 'ai', 'High', 'Chandini', '', 1],
151	    ['Copilot ROI analysis', 'ai', 'High', 'Self', '', 0],
152	    ['AlHasbah KPIs review with Shabeer', 'gov', 'High', 'Shabeer', '', 1],
153	    ['I&TF Quarterly report — Wafa, Ayesha, Umme, Nixon, Chandini', 'gov', 'Urgent', '', '2026-03-27', 0],
154	    ['EVP asked for MD Finance Agent', 'adhoc', 'Urgent', '', '', 0],
155	    ['WEF Lighthouse document — shared with Hamid and Ahmad AlShehhi', 'events', 'High', 'Hamid', '', 1],
156	    ['Check Udemy license distribution across divisions', 'ai', 'Medium', '', '', 0],
157	    ['GitHub Copilot end-to-end plan', 'ai', 'High', '', '', 0],
158	    ['Benchmark presentation meeting on 13 Apr', 'gov', 'High', 'Hamid', '2026-04-13', 1],
159	    ['Polynome NDA to be signed', 'vendor', 'High', '', '', 1],
160	    ['AI Ethics & Governance workshop for AI Champions', 'ai', 'High', '', '', 0],
161	    ['Copilot Studio Kit demo with Yasa', 'ai', 'High', 'Yasa', '', 0],
162	    ['Check with Microsoft to connect Viva Learning team', 'vendor', 'Medium', '', '', 0],
163	    ['D2D issue still open', 'strategic', 'High', '', '', 0],
164	    ['Staff mobile allowance', 'people', 'Medium', '', '', 0],
165	    ['Universities update', 'events', 'Medium', '', '', 0],
166	    ['Follow up on Anthropic contacts', 'vendor', 'High', '', '', 1],
167	    ['Genspark credit issue resolution', 'vendor', 'Medium', '', '', 1],
168	    ['Survey for AI Champions — measure performance', 'ai', 'High', '', '', 0],
169	  ];
170
171	  const seedTasks = db.transaction(() => {
172	    for (const t of tasks) insertTask.run(...t);
173	  });
174	  seedTasks();
175
176	}
177
178	function seedPeopleV2() {
179	  const already = db.prepare("SELECT value FROM settings WHERE key = 'people_v2'").get();
180	  if (already) return;
181	  db.prepare('DELETE FROM people').run();
182	  const ins = db.prepare('INSERT OR IGNORE INTO people (name, pr_number, designation) VALUES (?, ?, ?)');
183	  const members = [
184	    ['Ayesha Mohd Ali Sarwashi',              '15610',    'Specialist - Digital Services'],
185	    ['Saleha Obaid Essa',                      '24290',    'Sr Demand Analyst'],
186	    ['Mohammad Saif Bin Sulaiman',             '29433',    'Sr Engr - Digital Asset Mgmt'],
187	    ['Eiman Abdulla Alkindi',                  '23463',    'Sr Engr - Projects Govrnce'],
188	    ['Ahmad Mohamad Bin Dakhan',               '25260',    'Sr Exec - Digital Comm'],
189	    ['Noora Hassan Abdullatif Alsarah',        '24743',    'Sr Officer - Digital Products Mgmt'],
190	    ['Ahmed Saleh Ahmed Alshehhi',             '22990',    'Sr Exec - Customer Haps'],
191	    ['Wafa Mohd Mubarak Albalooshi',           '24911',    'Sr Exec - Admin'],
192	    ['Ayesha Eissa Humaid Abdulla Alzaabi',    '26971',    'Sr Exec - Admin'],
193	    ['Shamsa Ahmad Abdulla Alabdulla',         '29509',    'Sr Officer - Portfolio Delivery Mgmt'],
194	    ['Abdulla Almuhairi',                      '14933',    'Sr Exec - Digital Products Mgmt'],
195	    ['Majed Ahmed Mohamed Almarzouqi',         '30523',    'Analyst - Business Relationship Mgmt'],
196	    ['Khalid Abdulmunem Ibrahim Bin Kalban',   '29184',    'Mgr - Digital Products Mgmt'],
197	    ['Hamid Jasim Ahmed Mohamed Al-Ali',       '29295',    'Asst Mgr - Future Foresight Tech'],
198	    ['Elsa Prakash',                           '25297',    'Sr Analyst - Digital Product Mgmt'],
199	    ['Ummehani Rangwala',                      '99007665', 'External Contractor'],
200	    ['Rakesh Gulaganji',                       '99009102', 'External Contractor'],
201	    ['Prasanth Pillai',                        '99009407', 'External Contractor'],
202	    ['Marouane Basta',                         '99000698', 'External Contractor'],
203	    ['Ismail',                                 '',         'External Contractor'],
204	    ['Chandini',                               '',         'External Contractor'],
205	    ['Saravana Kumar',                         '',         'External Contractor'],
206	    ['Nixson Jesuraj',                         '',         'External Contractor'],
207	    ['Ankur Jain',                             '',         'External Contractor'],
208	    ['Anusha',                                 '',         'External Contractor'],
209	    ['Nora',                                   '',         'External Contractor'],
210	    ['Ashwin Kaleeswaran',                     '',         'External Contractor'],
211	    ['Fatehali',                               '',         'External Contractor'],
212	    ['Tharakeswar',                            '',         'External Contractor'],
213	    ['Kamalesh',                               '',         'External Contractor'],
214	    ['Kamlesh Manker',                         '99006876', 'External Contractor'],
215	  ];
216	  db.transaction(() => { for (const [n, p, d] of members) ins.run(n, p, d); })();
217	  db.prepare("INSERT OR REPLACE INTO settings (key, value) VALUES ('people_v2', 'true')").run();
218	  console.log('✅ People seeded (v2) — 31 team members');
219	}
220
221	initDb();
222	seedPeopleV2();
223
224	module.exports = db;
225

const Database = require('better-sqlite3');
const path = require('path');
const fs = require('fs');

const DB_PATH = path.join(__dirname, '../data/workspace.db');
const dataDir = path.dirname(DB_PATH);
if (!fs.existsSync(dataDir)) fs.mkdirSync(dataDir, { recursive: true });

const db = new Database(DB_PATH);
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');

// Migrate people table — add columns if not present
;['pr_number','grade','designation','department','section','reporting_line','mobile_number','place'].forEach(col => {
  try { db.exec(`ALTER TABLE people ADD COLUMN ${col} TEXT DEFAULT ''`); } catch {}
});

function initDb() {
  db.exec(`
    CREATE TABLE IF NOT EXISTS projects (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL,
      category TEXT NOT NULL DEFAULT 'adhoc',
      status TEXT NOT NULL DEFAULT 'Open',
      priority TEXT NOT NULL DEFAULT 'Medium',
      description TEXT DEFAULT '',
      last_update TEXT DEFAULT '',
      next_step TEXT DEFAULT '',
      created_at TEXT DEFAULT (datetime('now')),
      updated_at TEXT DEFAULT (datetime('now'))
    );

    CREATE TABLE IF NOT EXISTS tasks (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT NOT NULL,
      notes TEXT DEFAULT '',
      project_id INTEGER REFERENCES projects(id) ON DELETE SET NULL,
      category TEXT NOT NULL DEFAULT 'adhoc',
      priority TEXT NOT NULL DEFAULT 'Medium',
      status TEXT NOT NULL DEFAULT 'Open',
      assignee TEXT DEFAULT '',
      due_date TEXT DEFAULT '',
      is_follow_up INTEGER DEFAULT 0,
      is_today_focus INTEGER DEFAULT 0,
      completed_at TEXT DEFAULT '',
      created_at TEXT DEFAULT (datetime('now')),
      updated_at TEXT DEFAULT (datetime('now'))
    );

    CREATE TABLE IF NOT EXISTS notes (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT NOT NULL,
      body TEXT DEFAULT '',
      project_id INTEGER REFERENCES projects(id) ON DELETE SET NULL,
      date TEXT DEFAULT (date('now')),
      created_at TEXT DEFAULT (datetime('now'))
    );

    CREATE TABLE IF NOT EXISTS people (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      name TEXT NOT NULL UNIQUE,
      role TEXT DEFAULT '',
      created_at TEXT DEFAULT (datetime('now'))
    );

    CREATE TABLE IF NOT EXISTS settings (
      key TEXT PRIMARY KEY,
      value TEXT
    );

    CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status);
    CREATE INDEX IF NOT EXISTS idx_tasks_project ON tasks(project_id);
    CREATE INDEX IF NOT EXISTS idx_tasks_today ON tasks(is_today_focus);
    CREATE INDEX IF NOT EXISTS idx_tasks_followup ON tasks(is_follow_up);
    CREATE INDEX IF NOT EXISTS idx_projects_category ON projects(category);
    CREATE INDEX IF NOT EXISTS idx_notes_date ON notes(date);
  `);

  const seeded = db.prepare("SELECT value FROM settings WHERE key = 'seeded'").get();
  if (!seeded) {
    seedData();
    db.prepare("INSERT INTO settings (key, value) VALUES ('seeded', 'true')").run();
    console.log('✅ Database seeded with initial data');
  }
}

function seedData() {
  const insertProject = db.prepare(`
    INSERT INTO projects (name, category, status, priority) VALUES (?, ?, ?, ?)
  `);

  const projects = [
    // AI Adoption & Strategy
    ['Microsoft Copilot Rollout', 'ai', 'In Progress', 'High'],
    ['DEWA AI Academy', 'ai', 'In Progress', 'High'],
    ['AI Command Center RFP', 'ai', 'Open', 'High'],
    ['AI Champions Program', 'ai', 'In Progress', 'High'],
    ['AI OS Initiative', 'ai', 'In Progress', 'Urgent'],
    ['COE End-to-End', 'ai', 'In Progress', 'High'],
    ['GitHub Copilot Plan', 'ai', 'Open', 'High'],
    ['WalkMe & SAP Joule', 'ai', 'In Progress', 'Medium'],
    ['Rummana at Work', 'ai', 'Open', 'Medium'],
    ['Blink App AI Adoption', 'ai', 'Open', 'Medium'],
    // Vendor & Partnerships
    ['Google Partnership & NDA', 'vendor', 'Waiting', 'Urgent'],
    ['Polynome Engagement', 'vendor', 'In Progress', 'High'],
    ['Genspark Engagement', 'vendor', 'Waiting', 'Medium'],
    ['IMD Proposal', 'vendor', 'Open', 'Medium'],
    ['Ducont Wave 2', 'vendor', 'In Progress', 'High'],
    ['ElevenLabs Engagement', 'vendor', 'Open', 'Medium'],
    ['Dell Engagement', 'vendor', 'Open', 'Medium'],
    ['Coursera / Udemy Licenses', 'vendor', 'In Progress', 'Medium'],
    // Governance & Reporting
    ['I&TF Quarterly Report', 'gov', 'In Progress', 'Urgent'],
    ['AI Charter & ISO 42001', 'gov', 'Open', 'High'],
    ['KPIs & Blueprint', 'gov', 'In Progress', 'High'],
    ['IETF Benchmark', 'gov', 'In Progress', 'High'],
    // People & Team
    ['Employees Rating', 'people', 'Open', 'High'],
    ['Data Champions Program', 'people', 'Open', 'Medium'],
    ['Outsource Assessment', 'people', 'In Progress', 'Medium'],
    ['AI Ambassadors Survey', 'people', 'In Progress', 'High'],
    // Events & External
    ['WEF Lighthouse', 'events', 'Open', 'High'],
    ['Gartner Data Summit', 'events', 'Open', 'Medium'],
    ['GenAI Week Emirates Towers', 'events', 'Open', 'Medium'],
    ['Microsoft Community Conference', 'events', 'Open', 'Medium'],
    // Strategic Initiatives
    ['AlHasbah Use Cases Phase I', 'strategic', 'In Progress', 'High'],
    ['Digital DEWA Direction', 'strategic', 'Open', 'High'],
    ['D2D Workshop', 'strategic', 'In Progress', 'High'],
    ['AICC ROI Tracking', 'strategic', 'Open', 'High'],
    // CAIO / EVP Ad Hoc
    ['EVP MD Finance Agent', 'adhoc', 'Open', 'Urgent'],
    ['CAIO AI OS Initiative', 'adhoc', 'In Progress', 'High'],
  ];

  const seedProjects = db.transaction(() => {
    for (const p of projects) insertProject.run(...p);
  });
  seedProjects();

  const insertTask = db.prepare(`
    INSERT INTO tasks (title, category, priority, assignee, due_date, is_follow_up, status)
    VALUES (?, ?, ?, ?, ?, ?, 'Open')
  `);

  const tasks = [
    ['Google NDA: meet Legal Affairs + Hadi + CAIO', 'vendor', 'Urgent', 'Hadi', '', 1],
    ['Chandini to provide process map of features announcement', 'ai', 'High', 'Chandini', '', 1],
    ['Copilot ROI analysis', 'ai', 'High', 'Self', '', 0],
    ['AlHasbah KPIs review with Shabeer', 'gov', 'High', 'Shabeer', '', 1],
    ['I&TF Quarterly report — Wafa, Ayesha, Umme, Nixon, Chandini', 'gov', 'Urgent', '', '2026-03-27', 0],
    ['EVP asked for MD Finance Agent', 'adhoc', 'Urgent', '', '', 0],
    ['WEF Lighthouse document — shared with Hamid and Ahmad AlShehhi', 'events', 'High', 'Hamid', '', 1],
    ['Check Udemy license distribution across divisions', 'ai', 'Medium', '', '', 0],
    ['GitHub Copilot end-to-end plan', 'ai', 'High', '', '', 0],
    ['Benchmark presentation meeting on 13 Apr', 'gov', 'High', 'Hamid', '2026-04-13', 1],
    ['Polynome NDA to be signed', 'vendor', 'High', '', '', 1],
    ['AI Ethics & Governance workshop for AI Champions', 'ai', 'High', '', '', 0],
    ['Copilot Studio Kit demo with Yasa', 'ai', 'High', 'Yasa', '', 0],
    ['Check with Microsoft to connect Viva Learning team', 'vendor', 'Medium', '', '', 0],
    ['D2D issue still open', 'strategic', 'High', '', '', 0],
    ['Staff mobile allowance', 'people', 'Medium', '', '', 0],
    ['Universities update', 'events', 'Medium', '', '', 0],
    ['Follow up on Anthropic contacts', 'vendor', 'High', '', '', 1],
    ['Genspark credit issue resolution', 'vendor', 'Medium', '', '', 1],
    ['Survey for AI Champions — measure performance', 'ai', 'High', '', '', 0],
  ];

  const seedTasks = db.transaction(() => {
    for (const t of tasks) insertTask.run(...t);
  });
  seedTasks();

}

function seedPeopleV2() {
  const already = db.prepare("SELECT value FROM settings WHERE key = 'people_v2'").get();
  if (already) return;
  db.prepare('DELETE FROM people').run();
  const ins = db.prepare('INSERT OR IGNORE INTO people (name, pr_number, designation) VALUES (?, ?, ?)');
  const members = [
    ['Ayesha Mohd Ali Sarwashi',              '15610',    'Specialist - Digital Services'],
    ['Saleha Obaid Essa',                      '24290',    'Sr Demand Analyst'],
    ['Mohammad Saif Bin Sulaiman',             '29433',    'Sr Engr - Digital Asset Mgmt'],
    ['Eiman Abdulla Alkindi',                  '23463',    'Sr Engr - Projects Govrnce'],
    ['Ahmad Mohamad Bin Dakhan',               '25260',    'Sr Exec - Digital Comm'],
    ['Noora Hassan Abdullatif Alsarah',        '24743',    'Sr Officer - Digital Products Mgmt'],
    ['Ahmed Saleh Ahmed Alshehhi',             '22990',    'Sr Exec - Customer Haps'],
    ['Wafa Mohd Mubarak Albalooshi',           '24911',    'Sr Exec - Admin'],
    ['Ayesha Eissa Humaid Abdulla Alzaabi',    '26971',    'Sr Exec - Admin'],
    ['Shamsa Ahmad Abdulla Alabdulla',         '29509',    'Sr Officer - Portfolio Delivery Mgmt'],
    ['Abdulla Almuhairi',                      '14933',    'Sr Exec - Digital Products Mgmt'],
    ['Majed Ahmed Mohamed Almarzouqi',         '30523',    'Analyst - Business Relationship Mgmt'],
    ['Khalid Abdulmunem Ibrahim Bin Kalban',   '29184',    'Mgr - Digital Products Mgmt'],
    ['Hamid Jasim Ahmed Mohamed Al-Ali',       '29295',    'Asst Mgr - Future Foresight Tech'],
    ['Elsa Prakash',                           '25297',    'Sr Analyst - Digital Product Mgmt'],
    ['Ummehani Rangwala',                      '99007665', 'External Contractor'],
    ['Rakesh Gulaganji',                       '99009102', 'External Contractor'],
    ['Prasanth Pillai',                        '99009407', 'External Contractor'],
    ['Marouane Basta',                         '99000698', 'External Contractor'],
    ['Ismail',                                 '',         'External Contractor'],
    ['Chandini',                               '',         'External Contractor'],
    ['Saravana Kumar',                         '',         'External Contractor'],
    ['Nixson Jesuraj',                         '',         'External Contractor'],
    ['Ankur Jain',                             '',         'External Contractor'],
    ['Anusha',                                 '',         'External Contractor'],
    ['Nora',                                   '',         'External Contractor'],
    ['Ashwin Kaleeswaran',                     '',         'External Contractor'],
    ['Fatehali',                               '',         'External Contractor'],
    ['Tharakeswar',                            '',         'External Contractor'],
    ['Kamalesh',                               '',         'External Contractor'],
    ['Kamlesh Manker',                         '99006876', 'External Contractor'],
  ];
  db.transaction(() => { for (const [n, p, d] of members) ins.run(n, p, d); })();
  db.prepare("INSERT OR REPLACE INTO settings (key, value) VALUES ('people_v2', 'true')").run();
  console.log('✅ People seeded (v2) — 31 team members');
}

initDb();
seedPeopleV2();

module.exports = db;


Let me read the components to find the warnings.


1	import { useState, useEffect, useCallback } from 'react';
2	import {
3	  DndContext, DragOverlay, useDroppable, useDraggable,
4	  PointerSensor, TouchSensor, useSensor, useSensors, closestCenter
5	} from '@dnd-kit/core';
6	import {
7	  Plus, User, Calendar, ArrowRight, FolderKanban,
8	  CheckSquare, Bell, Target, AlertTriangle, MoreHorizontal, GripVertical, PenLine, Send
9	} from 'lucide-react';
10	import { Link, useNavigate } from 'react-router-dom';
11	import toast from 'react-hot-toast';
12	import api from '../api';
13	import TaskModal from './TaskModal';
14	import ConfirmDialog from './ConfirmDialog';
15	import { getCategoryClass, getPriorityClass, CATEGORIES, formatDate, isOverdue } from '../utils';
16
17	// ── Column config ────────────────────────────────────────────────────────────
18	const COLUMNS = [
19	  { id: 'focus',      title: "Today's Focus", color: 'text-primary',    bg: 'bg-primary/10',  border: 'border-l-primary'  },
20	  { id: 'inprogress', title: 'In Progress',   color: 'text-blue-600',   bg: 'bg-blue-50 dark:bg-blue-900/20',   border: 'border-l-blue-400'   },
21	  { id: 'followups',  title: 'Follow-ups',    color: 'text-amber-600',  bg: 'bg-amber-50 dark:bg-amber-900/20', border: 'border-l-amber-400'  },
22	  { id: 'open',       title: 'Open',          color: 'text-gray-500',   bg: 'bg-gray-100 dark:bg-gray-800',     border: 'border-l-gray-300'   },
23	];
24
25	const PRIORITY_BORDER = { Urgent:'border-l-red-500', High:'border-l-amber-400', Medium:'border-l-blue-400', Low:'border-l-green-400' };
26
27	function getColumnId(task) {
28	  if (task.status === 'Done') return null;
29	  if (task.is_today_focus)    return 'focus';
30	  if (task.status === 'In Progress') return 'inprogress';
31	  if (task.is_follow_up)      return 'followups';
32	  return 'open';
33	}
34
35	function columnUpdates(col, task) {
36	  const base = { ...task };
37	  if (col === 'focus')      return { ...base, is_today_focus: 1 };
38	  if (col === 'inprogress') return { ...base, status: 'In Progress', is_today_focus: 0 };
39	  if (col === 'followups')  return { ...base, is_follow_up: 1,  is_today_focus: 0 };
40	  if (col === 'open')       return { ...base, is_today_focus: 0, status: 'Open' };
41	  return base;
42	}
43
44	// ── Draggable card ───────────────────────────────────────────────────────────
45	function DraggableCard({ task, onEdit, onDelete, onMarkDone }) {
46	  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({ id: task.id });
47	  const overdue = isOverdue(task.due_date);
48
49	  return (
50

58

59

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

67

68
{task.title}

69	              <button onClick={() => onEdit(task)}
70	                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">
71	                <MoreHorizontal size={13} />
72	              </button>
73

74
75	            {task.notes &&
{task.notes}
}
76
77

78	              <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
79	                {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}
80
81	              <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
82	              {task.is_follow_up === 1 && Follow-up}
83

84
85

86

87	                {task.assignee ? (
88

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

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

94

95	                {task.due_date && (
96	                  <span className={`flex items-center gap-0.5 text-[10px] ${overdue ? 'text-red-500 font-semibold' : 'text-gray-400'}`}>
97	                    {overdue && <AlertTriangle size={9} />}{formatDate(task.due_date)}
98
99	                )}
100	                <button onClick={() => onMarkDone(task)}
101	                  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">
102	                  Done
103	                </button>
104

105

106

107

108

109

110	  );
111	}
112
113	// ── Drag overlay card (ghost while dragging) ─────────────────────────────────
114	function OverlayCard({ task }) {
115	  return (
116

118
{task.title}

119

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

125

126	  );
127	}
128
129	// ── Droppable column ─────────────────────────────────────────────────────────
130	function DroppableColumn({ col, tasks, stats, onAddTask, onEdit, onDelete, onMarkDone }) {
131	  const { setNodeRef, isOver } = useDroppable({ id: col.id });
132
133	  return (
134

138	      {/* Column header */}
139

140

141
{col.title}

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

144	        <button onClick={onAddTask}
145	          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">
146	          <Plus size={12} />
147	        </button>
148

149
150	      {/* Cards */}
151

152	        {tasks.length === 0 ? (
153

155
Drop here

156

157	        ) : (
158	          tasks.map(task => (
159	            <DraggableCard key={task.id} task={task} onEdit={onEdit} onDelete={onDelete} onMarkDone={onMarkDone} />
160	          ))
161	        )}
162

163

164	  );
165	}
166
167	// ── Main Dashboard ───────────────────────────────────────────────────────────
168	export default function Today() {
169	  const [allTasks, setAllTasks]     = useState([]);
170	  const [stats, setStats]           = useState(null);
171	  const [projects, setProjects]     = useState([]);
172	  const [loading, setLoading]       = useState(true);
173	  const [editTask, setEditTask]     = useState(null);
174	  const [deleteTask, setDeleteTask] = useState(null);
175	  const [showNew, setShowNew]       = useState(false);
176	  const [newDefaults, setNewDefaults] = useState({});
177	  const [activeTask, setActiveTask] = useState(null);
178	  const [activeTab, setActiveTab]   = useState('dashboard');
179	  const [quickInput, setQuickInput] = useState('');
180	  const navigate = useNavigate();
181
182	  const today = new Date();
183	  const dateLabel = today.toLocaleDateString('en-GB', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
184
185	  const load = useCallback(async () => {
186	    try {
187	      const [tasks, st, pr] = await Promise.all([api.get('/tasks'), api.get('/tasks/stats'), api.get('/projects')]);
188	      setAllTasks(tasks); setStats(st); setProjects(pr);
189	    } finally { setLoading(false); }
190	  }, []);
191
192	  useEffect(() => { load(); }, [load]);
193
194	  // Bucket tasks into columns
195	  const columns = COLUMNS.map(col => ({
196	    ...col,
197	    tasks: allTasks.filter(t => getColumnId(t) === col.id),
198	  }));
199
200	  // DnD sensors — support mouse, touch (mobile), delay to prevent accidental drags
201	  const sensors = useSensors(
202	    useSensor(PointerSensor, { activationConstraint: { distance: 8 } }),
203	    useSensor(TouchSensor,   { activationConstraint: { delay: 180, tolerance: 6 } })
204	  );
205
206	  const onDragStart = ({ active }) => {
207	    setActiveTask(allTasks.find(t => t.id === active.id) || null);
208	  };
209
210	  const onDragEnd = async ({ active, over }) => {
211	    setActiveTask(null);
212	    if (!over) return;
213	    const task = allTasks.find(t => t.id === active.id);
214	    if (!task) return;
215	    const targetCol = COLUMNS.find(c => c.id === over.id);
216	    if (!targetCol || getColumnId(task) === targetCol.id) return;
217
218	    // Optimistic update
219	    const updated = columnUpdates(targetCol.id, task);
220	    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, ...updated } : t));
221	    try {
222	      await api.put(`/tasks/${task.id}`, updated);
223	      toast.success(`Moved to "${targetCol.title}"`);
224	    } catch (e) {
225	      toast.error('Failed to move task'); load();
226	    }
227	  };
228
229	  const markDone = async (task) => {
230	    setAllTasks(prev => prev.map(t => t.id === task.id ? { ...t, status: 'Done' } : t));
231	    await api.patch(`/tasks/${task.id}/status`, { status: 'Done' });
232	    toast.success('Marked as done');
233	  };
234
235	  const openNew = (defaults = {}) => { setNewDefaults(defaults); setShowNew(true); }
236
237	  const quickCapture = async (e) => {
238	    e.preventDefault();
239	    const title = quickInput.trim();
240	    if (!title) return;
241	    try {
242	      await api.post('/tasks', { title, priority: 'Medium', status: 'Open', category: 'adhoc', is_today_focus: 1 });
243	      setQuickInput('');
244	      toast.success('Task added to Today\'s Focus');
245	      load();
246	    } catch { toast.error('Failed to add task'); }
247	  };;
248
249	  const handleSave = async (form) => {
250	    try {
251	      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
252	      else { await api.post('/tasks', { ...form, ...newDefaults }); toast.success('Task added'); }
253	      setEditTask(null); setShowNew(false); load();
254	    } catch (e) { toast.error(e.message); }
255	  };
256
257	  const handleDelete = async () => {
258	    await api.delete(`/tasks/${deleteTask.id}`);
259	    toast.success('Deleted'); setDeleteTask(null); load();
260	  };
261
262	  const TABS = [
263	    { id: 'dashboard', label: 'Dashboard' },
264	    { id: 'all',       label: 'All Tasks'      },
265	    { id: 'projects',  label: 'Projects'       },
266	  ];
267
268	  return (
269

270
271	      {/* Hero banner */}
272

273

274

275

276

277

278
DEWA AI Workspace

279
{dateLabel}

280

281

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

289
{value}

290

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

293

294	            ))}
295

296

297

298
299	      {/* Quick Capture bar */}
300

301	        <form onSubmit={quickCapture} className="flex items-center gap-2 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-2xl px-3 py-2 shadow-card focus-within:ring-2 focus-within:ring-primary/30 focus-within:border-primary/50 transition-all">
302	          <PenLine size={14} className="text-gray-400 shrink-0" />
303	          <input
304	            className="flex-1 bg-transparent text-sm text-gray-800 dark:text-gray-100 placeholder-gray-400 outline-none"
305	            placeholder="Capture a quick task… (Enter to add to Today's Focus)"
306	            value={quickInput}
307	            onChange={e => setQuickInput(e.target.value)}
308	          />
309	          {quickInput.trim() && (
310	            <button type="submit" className="shrink-0 flex items-center gap-1 px-2.5 py-1 bg-primary text-white text-xs font-medium rounded-xl hover:bg-primary/90 transition-colors">
311	              <Send size={11} /> Add
312	            </button>
313	          )}
314	          <button type="button" onClick={() => navigate('/inbox')}
315	            className="shrink-0 text-[10px] text-gray-400 hover:text-primary transition-colors whitespace-nowrap">
316	            AI Parse →
317	          </button>
318	        </form>
319

320
321	      {/* Tabs */}
322

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

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

338
339	      {/* ── Kanban Board (drag & drop) ─────────────────────────────────── */}
340	      {loading ? (
341

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

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

351	                {columns.map(col => (
352	                  <DroppableColumn
353	                    key={col.id} col={col} tasks={col.tasks}
354	                    onAddTask={() => openNew(
355	                      col.id === 'focus'      ? { is_today_focus: 1 } :
356	                      col.id === 'inprogress' ? { status: 'In Progress' } :
357	                      col.id === 'followups'  ? { is_follow_up: 1 } : {}
358	                    )}
359	                    onEdit={setEditTask}
360	                    onDelete={setDeleteTask}
361	                    onMarkDone={markDone}
362	                  />
363	                ))}
364

365	              {/* Drag overlay */}
366	              <DragOverlay dropAnimation={{ duration: 180, easing: 'cubic-bezier(0.18,0.67,0.6,1.22)' }}>
367	                {activeTask && <OverlayCard task={activeTask} />}
368	              </DragOverlay>
369	            </DndContext>
370	          )}
371
372	          {/* ALL TASKS — horizontal grid */}
373	          {activeTab === 'all' && (
374

375

376	                {allTasks.filter(t => t.status !== 'Done').map(task => (
377
 setEditTask(task)}>
381
{task.title}

382

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

388	                    {task.assignee && (
389

390

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

393	                        {task.assignee}
394

395	                    )}
396

397	                ))}
398

399

400	          )}
401
402	          {/* PROJECTS — horizontal grid */}
403	          {activeTab === 'projects' && (
404

405

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

410	                      <span className={`badge text-[10px] ${getCategoryClass(p.category)}`}>
411	                        {CATEGORIES[p.category]?.label?.split(' ')[0] || p.category}
412
413	                      <ArrowRight size={12} className="text-gray-300 group-hover:text-primary transition-colors" />
414

415
{p.name}

416

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

420	                  </button>
421	                ))}
422

423

424	          )}
425	        </>
426	      )}
427
428	      {/* Modals */}
429	      {(showNew || editTask) && (
430	        <TaskModal task={editTask} projects={projects} onSave={handleSave} onClose={() => { setShowNew(false); setEditTask(null); }} />
431	      )}
432	      {deleteTask && (
433	        <ConfirmDialog title="Delete task?" message={`"${deleteTask.title}"`} onConfirm={handleDelete} onCancel={() => setDeleteTask(null)} />
434	      )}
435

436	  );
437	}
438

import { useState, useEffect, useCallback } from 'react';
import {
  DndContext, DragOverlay, useDroppable, useDraggable,
  PointerSensor, TouchSensor, useSensor, useSensors, closestCenter
} from '@dnd-kit/core';
import {
  Plus, User, Calendar, ArrowRight, FolderKanban,
  CheckSquare, Bell, Target, AlertTriangle, MoreHorizontal, GripVertical, PenLine, Send
} 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 [quickInput, setQuickInput] = useState('');
  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 quickCapture = async (e) => {
    e.preventDefault();
    const title = quickInput.trim();
    if (!title) return;
    try {
      await api.post('/tasks', { title, priority: 'Medium', status: 'Open', category: 'adhoc', is_today_focus: 1 });
      setQuickInput('');
      toast.success('Task added to Today\'s Focus');
      load();
    } catch { toast.error('Failed to add task'); }
  };;

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

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}

            ))}

      {/* Quick Capture bar */}

        <form onSubmit={quickCapture} className="flex items-center gap-2 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-2xl px-3 py-2 shadow-card focus-within:ring-2 focus-within:ring-primary/30 focus-within:border-primary/50 transition-all">
          <PenLine size={14} className="text-gray-400 shrink-0" />
          <input
            className="flex-1 bg-transparent text-sm text-gray-800 dark:text-gray-100 placeholder-gray-400 outline-none"
            placeholder="Capture a quick task… (Enter to add to Today's Focus)"
            value={quickInput}
            onChange={e => setQuickInput(e.target.value)}
          />
          {quickInput.trim() && (
            <button type="submit" className="shrink-0 flex items-center gap-1 px-2.5 py-1 bg-primary text-white text-xs font-medium rounded-xl hover:bg-primary/90 transition-colors">
              <Send size={11} /> Add
            </button>
          )}
          <button type="button" onClick={() => navigate('/inbox')}
            className="shrink-0 text-[10px] text-gray-400 hover:text-primary transition-colors whitespace-nowrap">
            AI Parse →
          </button>
        </form>

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

  );
}


1	import { useState, useEffect, useRef } from 'react';
2	import { Plus, Search, SlidersHorizontal, CheckSquare, X, Check, Calendar, User, AlertTriangle } from 'lucide-react';
3	import toast from 'react-hot-toast';
4	import api from '../api';
5	import TaskCard from './TaskCard';
6	import TaskModal from './TaskModal';
7	import ConfirmDialog from './ConfirmDialog';
8	import { CATEGORIES, STATUSES, PRIORITIES, getCategoryClass, getPriorityClass, getStatusClass, formatDate, isOverdue } from '../utils';
9
10	const PRIORITY_BORDER = {
11	  Urgent: 'border-l-red-500',
12	  High:   'border-l-amber-400',
13	  Medium: 'border-l-blue-400',
14	  Low:    'border-l-green-400',
15	};
16
17	function useDebounce(v, d = 300) {
18	  const [dv, setDv] = useState(v);
19	  useEffect(() => { const t = setTimeout(() => setDv(v), d); return () => clearTimeout(t); }, [v, d]);
20	  return dv;
21	}
22
23	// Status columns for horizontal kanban-style layout
24	const STATUS_COLS = [
25	  { id: '',          label: 'All',         color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
26	  { id: 'Open',      label: 'Open',        color: 'bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400' },
27	  { id: 'In Progress',label:'In Progress', color: 'bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-300' },
28	  { id: 'Waiting',   label: 'Waiting',     color: 'bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-300' },
29	  { id: 'Done',      label: 'Done',        color: 'bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-300' },
30	];
31
32	export default function Tasks() {
33	  const [tasks, setTasks]           = useState([]);
34	  const [projects, setProjects]     = useState([]);
35	  const [loading, setLoading]       = useState(true);
36	  const [search, setSearch]         = useState('');
37	  const [statusFilter, setStatus]   = useState('');
38	  const [catFilter, setCat]         = useState('');
39	  const [priorityFilter, setPri]    = useState('');
40	  const [showFilters, setShowFilters] = useState(false);
41	  const [editTask, setEditTask]     = useState(null);
42	  const [deleteTask, setDeleteTask] = useState(null);
43	  const [showNew, setShowNew]       = useState(false);
44	  const [selected, setSelected]     = useState(new Set());
45	  const [viewMode, setViewMode]     = useState('grid'); // 'grid' | 'kanban'
46	  const debouncedSearch = useDebounce(search);
47
48	  const load = async () => {
49	    setLoading(true);
50	    const p = new URLSearchParams();
51	    if (debouncedSearch)  p.set('search',   debouncedSearch);
52	    if (statusFilter)     p.set('status',   statusFilter);
53	    if (catFilter)        p.set('category', catFilter);
54	    if (priorityFilter)   p.set('priority', priorityFilter);
55	    try {
56	      const [t, pr] = await Promise.all([api.get('/tasks?' + p), api.get('/projects')]);
57	      setTasks(t); setProjects(pr);
58	    } finally { setLoading(false); }
59	  };
60
61	  useEffect(() => { load(); }, [debouncedSearch, statusFilter, catFilter, priorityFilter]);
62
63	  const handleSave = async (form) => {
64	    try {
65	      if (editTask?.id) { await api.put(`/tasks/${editTask.id}`, form); toast.success('Task updated'); }
66	      else              { await api.post('/tasks', form);               toast.success('Task added');   }
67	      setEditTask(null); setShowNew(false); load();
68	    } catch (e) { toast.error(e.message); }
69	  };
70
71	  const handleDelete = async () => {
72	    await api.delete(`/tasks/${deleteTask.id}`); toast.success('Deleted');
73	    setDeleteTask(null); load();
74	  };
75
76	  const toggleFocus = async (task) => { await api.patch(`/tasks/${task.id}/focus`); load(); };
77
78	  const toggleSelect = (id) => setSelected(s => {
79	    const n = new Set(s); n.has(id) ? n.delete(id) : n.add(id); return n;
80	  });
81
82	  const bulkDone = async () => {
83	    await Promise.all([...selected].map(id => api.patch(`/tasks/${id}/status`, { status: 'Done' })));
84	    toast.success(`${selected.size} tasks done`);
85	    setSelected(new Set()); load();
86	  };
87
88	  const hasFilters = statusFilter || catFilter || priorityFilter;
89
90	  // Kanban grouping by status
91	  const KANBAN_COLS = ['Open', 'In Progress', 'Waiting', 'Done'];
92	  const byStatus = KANBAN_COLS.reduce((acc, s) => {
93	    acc[s] = tasks.filter(t => t.status === s);
94	    return acc;
95	  }, {});
96
97	  return (
98

99
100	      {/* Header */}
101

102

103
Tasks

104

105	            {/* View toggle */}
106

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

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

120

121
122	        {/* Search + filter row */}
123

124

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

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

134
135	        {/* Filter chips */}
136	        {showFilters && (
137

138	            <select className="select text-xs py-1.5 w-auto" value={statusFilter} onChange={e => setStatus(e.target.value)}>
139	              <option value="">All Status</option>
140	              {STATUSES.map(s => <option key={s}>{s}</option>)}
141	            </select>
142	            <select className="select text-xs py-1.5 w-auto" value={catFilter} onChange={e => setCat(e.target.value)}>
143	              <option value="">All Categories</option>
144	              {Object.entries(CATEGORIES).map(([k, v]) => <option key={k} value={k}>{v.label}</option>)}
145	            </select>
146	            <select className="select text-xs py-1.5 w-auto" value={priorityFilter} onChange={e => setPri(e.target.value)}>
147	              <option value="">All Priorities</option>
148	              {PRIORITIES.map(p => <option key={p}>{p}</option>)}
149	            </select>
150	            {hasFilters && (
151	              <button onClick={() => { setStatus(''); setCat(''); setPri(''); }}
152	                className="flex items-center gap-1 text-xs text-primary hover:underline px-2">
153	                <X size={11} /> Clear
154	              </button>
155	            )}
156

157	        )}
158
159	        {/* Bulk actions */}
160	        {selected.size > 0 && (
161

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

168	        )}
169

170
171	      {/* Content area */}
172	      {loading ? (
173

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

176	      ) : tasks.length === 0 ? (
177

178	          <CheckSquare size={40} className="text-gray-200 dark:text-gray-700" />
179
No tasks found

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

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

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

190

191	            {tasks.map(task => {
192	              const overdue = isOverdue(task.due_date) && task.status !== 'Done';
193	              const isDone = task.status === 'Done';
194	              const isSelected = selected.has(task.id);
195	              return (
196
 setEditTask(task)}
200	                >
201

202

203	                      {/* Green checkbox inside card */}
204	                      <button
205	                        onClick={e => { e.stopPropagation(); toggleSelect(task.id); }}
206	                        className={`shrink-0 mt-0.5 w-5 h-5 rounded-md border-2 flex items-center justify-center transition-all ${
207	                          isSelected || isDone
208	                            ? 'bg-green-500 border-green-500 shadow-sm'
209	                            : 'border-gray-300 dark:border-gray-600 hover:border-green-400'
210	                        }`}
211	                      >
212	                        {(isSelected || isDone) && <Check size={11} className="text-white" />}
213	                      </button>
214
215

216	                        <p className={`text-sm font-semibold leading-snug ${isDone ? 'line-through text-gray-400' : 'text-gray-800 dark:text-gray-100'}`}>
217	                          {task.title}
218

219	                        {task.notes && (
220
{task.notes}

221	                        )}
222

223	                          <span className={`badge text-[10px] py-0.5 ${getPriorityClass(task.priority)}`}>{task.priority}
224	                          <span className={`badge text-[10px] py-0.5 ${getCategoryClass(task.category)}`}>
225	                            {CATEGORIES[task.category]?.label?.split(' ')[0] || task.category}
226
227	                          <span className={`badge text-[10px] py-0.5 ${getStatusClass(task.status)}`}>{task.status}
228

229	                        {(task.assignee || task.due_date) && (
230

231	                            {task.assignee && (
232
233	                                <User size={10} />{task.assignee}
234
235	                            )}
236	                            {task.due_date && (
237	                              <span className={`flex items-center gap-1 ${overdue ? 'text-red-500 font-medium' : ''}`}>
238	                                {overdue && <AlertTriangle size={10} />}
239	                                <Calendar size={10} />{formatDate(task.due_date)}
240
241	                            )}
242

243	                        )}
244

245

246

247

248	              );
249	            })}
250

251

252	      ) : (
253	        /* ── KANBAN / BOARD view ────────────────────────── */
254

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

262

263

264
{status}

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

267	                  <button onClick={() => setShowNew(true)}
268	                    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">
269	                    <Plus size={12} />
270	                  </button>
271

272

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

278
No tasks

279

280	                  )}
281

282

283	            );
284	          })}
285

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

295	  );
296	}
297

import { useState, useEffect, useRef } from 'react';
import { Plus, Search, SlidersHorizontal, CheckSquare, X, Check, Calendar, User, AlertTriangle } 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, getStatusClass, formatDate, isOverdue } from '../utils';

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

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 => {
              const overdue = isOverdue(task.due_date) && task.status !== 'Done';
              const isDone = task.status === 'Done';
              const isSelected = selected.has(task.id);
              return (

 setEditTask(task)}
                >

                      {/* Green checkbox inside card */}
                      <button
                        onClick={e => { e.stopPropagation(); toggleSelect(task.id); }}
                        className={`shrink-0 mt-0.5 w-5 h-5 rounded-md border-2 flex items-center justify-center transition-all ${
                          isSelected || isDone
                            ? 'bg-green-500 border-green-500 shadow-sm'
                            : 'border-gray-300 dark:border-gray-600 hover:border-green-400'
                        }`}
                      >
                        {(isSelected || isDone) && <Check size={11} className="text-white" />}
                      </button>

                        <p className={`text-sm font-semibold leading-snug ${isDone ? 'line-through text-gray-400' : 'text-gray-800 dark:text-gray-100'}`}>
                          {task.title}

                        {task.notes && (

{task.notes}

                        )}

                          <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.category}

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

                        {(task.assignee || task.due_date) && (

                            {task.assignee && (

                                <User size={10} />{task.assignee}

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

                            )}

                        )}

              );
            })}

      ) : (
        /* ── 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)} />
      )}

  );
}


Let me read the remaining components to find all warnings.