import { useState } from 'react';
import type { Task, User, Status, Priority } from './data';
import { STATUS_LABELS, getUserById } from './data';
import { Avatar, Tag, ProgressBar } from './Shared';
interface DrawerProps {
task: Task; currentUser: User; onClose: () => void;
onUpdate: (updated: Task) => void;
onAddDependency: (taskId: string, dep: { dependsOnUserId: string; description: string }) => void;
onToggleDependency: (taskId: string, depId: string, resolved: boolean) => void;
onRemoveDependency: (taskId: string, depId: string) => void;
users: User[];
}
export function TaskDrawer({ task, currentUser, onClose, onUpdate, onAddDependency, onToggleDependency, onRemoveDependency, users }: DrawerProps) {
const [commentText, setCommentText] = useState('');
const [subtaskText, setSubtaskText] = useState('');
const [depUser, setDepUser] = useState('');
const [depDesc, setDepDesc] = useState('');
const updateField = (field: string, value: any) => {
const now = new Date().toISOString();
const updated = {
...task, [field]: value,
activity: [...task.activity, { id: `a${Date.now()}`, text: `๐ ${currentUser.name} changed ${field} to ${value}`, timestamp: now }]
};
onUpdate(updated);
};
const toggleSubtask = (sid: string) => {
const now = new Date().toISOString();
const subtasks = task.subtasks.map(s => s.id === sid ? { ...s, done: !s.done } : s);
const st = subtasks.find(s => s.id === sid)!;
onUpdate({
...task, subtasks,
activity: [...task.activity, { id: `a${Date.now()}`, text: `${st.done ? 'โ
' : 'โฉ๏ธ'} ${currentUser.name} ${st.done ? 'completed' : 'unchecked'} subtask "${st.title}"`, timestamp: now }]
});
};
const addSubtask = () => {
if (!subtaskText.trim()) return;
onUpdate({ ...task, subtasks: [...task.subtasks, { id: `s${Date.now()}`, title: subtaskText, done: false }] });
setSubtaskText('');
};
const addComment = () => {
if (!commentText.trim()) return;
const now = new Date().toISOString();
onUpdate({
...task,
comments: [...task.comments, { id: `c${Date.now()}`, userId: currentUser.id, text: commentText, timestamp: now }],
activity: [...task.activity, { id: `a${Date.now()}`, text: `๐ฌ ${currentUser.name} added a comment`, timestamp: now }]
});
setCommentText('');
};
const handleAddDep = () => {
if (!depDesc.trim()) return;
onAddDependency(task.id, { dependsOnUserId: depUser, description: depDesc });
setDepDesc('');
setDepUser('');
};
const reporter = getUserById(users, task.reporter);
const doneCount = task.subtasks.filter(s => s.done).length;
const unresolvedDeps = (task.dependencies || []).filter(d => !d.resolved).length;
return (
<>
Task Detail
{task.title}
{task.description}
Assignee
Status
Priority
Tags
{task.tags.map(t => )}
{/* Dependencies Section */}
๐ Dependencies
{unresolvedDeps > 0 && {unresolvedDeps} blocking}
{(task.dependencies || []).length === 0 && (
No dependencies yet
)}
{(task.dependencies || []).map(dep => {
const depUser = getUserById(users, dep.dependsOnUserId);
return (
{depUser && (
{depUser.name}
)}
{dep.description}
);
})}
setDepDesc(e.target.value)} onKeyDown={e => e.key === 'Enter' && handleAddDep()} />
Subtasks {doneCount} of {task.subtasks.length} complete
{task.subtasks.length > 0 &&
}
{task.subtasks.map(s => (
toggleSubtask(s.id)}>
{s.title}
))}
setSubtaskText(e.target.value)} onKeyDown={e => e.key === 'Enter' && addSubtask()} />
Comments
{task.comments.map(c => {
const cu = getUserById(users, c.userId);
return (
{cu?.name}
{new Date(c.timestamp).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
{c.text}
);
})}
Activity
{task.activity.map(a => (
{a.text} ยท {new Date(a.timestamp).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' })}
))}
>
);
}
interface ModalProps {
onClose: () => void;
onAdd: (task: Task) => void;
defaultDate?: string;
defaultStatus?: Status;
users: User[];
currentUser: User;
}
interface PendingDep {
id: string;
dependsOnUserId: string;
description: string;
}
export function AddTaskModal({ onClose, onAdd, defaultDate, defaultStatus, users, currentUser }: ModalProps) {
const [title, setTitle] = useState('');
const [desc, setDesc] = useState('');
const [assignee, setAssignee] = useState(currentUser.id);
const [priority, setPriority] = useState('medium');
const [status, setStatus] = useState(defaultStatus || 'todo');
const [dueDate, setDueDate] = useState(defaultDate || new Date().toISOString().split('T')[0]);
const [tags, setTags] = useState('');
const [error, setError] = useState(false);
// Dependencies state
const [deps, setDeps] = useState([]);
const [depUser, setDepUser] = useState('');
const [depDesc, setDepDesc] = useState('');
const addDep = () => {
if (!depDesc.trim()) return;
setDeps(prev => [...prev, { id: `pd${Date.now()}`, dependsOnUserId: depUser, description: depDesc }]);
setDepDesc('');
setDepUser('');
};
const removeDep = (id: string) => {
setDeps(prev => prev.filter(d => d.id !== id));
};
const submit = () => {
if (!title.trim()) { setError(true); return; }
const task: Task = {
id: `t${Date.now()}`, title, description: desc, status, priority,
assignee, reporter: currentUser.id, dueDate,
tags: tags ? tags.split(',').map(t => t.trim()).filter(Boolean) : [],
subtasks: [], comments: [],
activity: [{ id: `a${Date.now()}`, text: `๐ Task created`, timestamp: new Date().toISOString() }],
dependencies: deps.map(d => ({ id: d.id, dependsOnUserId: d.dependsOnUserId, description: d.description, resolved: false })),
};
onAdd(task);
onClose();
};
return (
e.stopPropagation()}>
New Task
{ setTitle(e.target.value); setError(false); }} />
setDueDate(e.target.value)} />
setTags(e.target.value)} />
{/* Dependencies Section */}
{deps.map(d => {
const u = getUserById(users, d.dependsOnUserId);
return (
โณ
{u && {u.avatar} {u.name}:}
{d.description}
);
})}
setDepDesc(e.target.value)} onKeyDown={e => e.key === 'Enter' && (e.preventDefault(), addDep())} />
);
}