// ============================================================ // MOORE AI v13 — TASKS TAB (Internal Kanban Board) // Data stored in localStorage('moore_tasks') // Requires: shared/utils.js, shared/components.jsx loaded first // ============================================================ const TasksView = ({ tasks, setTasks }) => { const { useState, useMemo, useEffect } = React; // On mount: fetch any tasks queued from ElevenLabs calls and merge in useEffect(() => { API.fetchPendingTasks().then(data => { if (data.tasks && data.tasks.length > 0) { setTasks(prev => { const merged = [...data.tasks, ...prev]; localStorage.setItem('moore_tasks', JSON.stringify(merged)); return merged; }); } }).catch(() => {}); }, []); const [newTitle, setNewTitle] = useState(''); const [newPriority, setNewPriority] = useState('medium'); const [newContact, setNewContact] = useState(''); const [showForm, setShowForm] = useState(false); const COLUMNS = ['todo', 'in-progress', 'done']; const COLUMN_LABELS = { 'todo': 'Todo', 'in-progress': 'In Progress', 'done': 'Done' }; const COLUMN_COLORS = { 'todo': '#3b82f6', 'in-progress': '#f59e0b', 'done': '#10b981' }; const priorityColors = { high: 'bg-red-950/30 text-red-400 border-red-700/40', medium: 'bg-amber-950/30 text-amber-400 border-amber-700/40', low: 'bg-slate-900/30 text-slate-400 border-slate-700/40' }; const sourceBadge = { 'AI Generated': 'text-indigo-400 bg-indigo-950/30 border-indigo-700/30', 'Manual': 'text-slate-400 bg-slate-900/40 border-slate-700/30', 'From Call': 'text-teal-400 bg-teal-950/30 border-teal-700/30' }; const saveTasks = (updated) => { setTasks(updated); localStorage.setItem('moore_tasks', JSON.stringify(updated)); }; const addTask = () => { if (!newTitle.trim()) return; const task = { id: Date.now(), title: newTitle.trim(), priority: newPriority, contact: newContact.trim(), status: 'todo', source: 'Manual', createdAt: new Date().toISOString() }; saveTasks([task, ...tasks]); setNewTitle(''); setNewContact(''); setNewPriority('medium'); setShowForm(false); }; const moveTask = (id, newStatus) => { saveTasks(tasks.map(t => t.id === id ? { ...t, status: newStatus } : t)); }; const deleteTask = (id) => { saveTasks(tasks.filter(t => t.id !== id)); }; const columnTasks = (col) => tasks.filter(t => t.status === col); const openCount = tasks.filter(t => t.status !== 'done').length; return (
{/* Header */}
Internal Board

Tasks

{openCount > 0 && ( {openCount} open )}
{/* Quick add form */} {showForm && (
setNewTitle(e.target.value)} onKeyDown={e => e.key === 'Enter' && addTask()} placeholder="Task title..." className="flex-1 min-w-48 bg-slate-900/80 border border-slate-700/60 rounded-xl px-4 py-2 text-sm text-white outline-none focus:border-blue-500/50 placeholder:text-slate-600" /> setNewContact(e.target.value)} placeholder="Contact (optional)" className="w-44 bg-slate-900/80 border border-slate-700/60 rounded-xl px-3 py-2 text-sm text-white outline-none focus:border-blue-500/50 placeholder:text-slate-600" />
)} {/* Kanban columns */}
{COLUMNS.map(col => (
{/* Column header */}
{COLUMN_LABELS[col]}
{columnTasks(col).length}
{/* Cards */}
{columnTasks(col).length === 0 && (
Empty
)} {columnTasks(col).map(task => (
{task.title}
{task.contact && (
{task.contact}
)}
{task.priority && ( {task.priority} )} {task.source && ( {task.source} )}
{col !== 'todo' && ( )} {col !== 'done' && ( )}
))}
))}
); };