feat: add task comments feature with CRUD operations

- Introduced a new `task_comments` table in the database schema.
- Implemented task comments API endpoints for listing, creating, and deleting comments.
- Enhanced the task detail dialog to display comments and allow users to add new comments.
- Updated task row component to handle click events for viewing task details.
- Added a theme provider to manage light/dark mode across the application.
- Refactored Milkdown editor to use Crepe for improved markdown editing experience.
- Updated global styles to accommodate new editor and theme changes.
- Enhanced task filtering and sorting functionality in the tasks page.
This commit is contained in:
Roberto Musso
2026-02-23 12:54:14 +01:00
parent 98acf6220e
commit c1aa6829c9
24 changed files with 996 additions and 234 deletions

View File

@@ -23,6 +23,7 @@ import {
import { Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription } from '@/components/ui/empty';
import { NewTaskDialog } from '@/components/tasks/NewTaskDialog';
import { EditTaskDialog } from '@/components/tasks/EditTaskDialog';
import { TaskDetailDialog } from '@/components/tasks/TaskDetailDialog';
import { TaskRow, type TaskItem } from '@/components/tasks/TaskRow';
export const Route = createFileRoute('/tasks')({
@@ -42,9 +43,10 @@ function TasksPage() {
const [search, setSearch] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const [statusFilter, setStatusFilter] = useState<StatusFilter>('all');
const [orderBy, setOrderBy] = useState<OrderBy>('createdAt');
const [orderBy, setOrderBy] = useState<OrderBy>('dueDate');
const [dialogOpen, setDialogOpen] = useState(false);
const [editTask, setEditTask] = useState<TaskItem | null>(null);
const [viewTask, setViewTask] = useState<TaskItem | null>(null);
const debounceTimer = useMemo(() => ({ id: null as ReturnType<typeof setTimeout> | null }), []);
@@ -127,7 +129,7 @@ function TasksPage() {
<ItemDescription>To Do</ItemDescription>
</ItemContent>
</Item>
<Item variant="muted" className="bg-sky-50">
<Item variant="muted" className="bg-sky-50 dark:bg-sky-950/30">
<ItemMedia variant="icon">
<Loader2 />
</ItemMedia>
@@ -136,7 +138,7 @@ function TasksPage() {
<ItemDescription>In Progress</ItemDescription>
</ItemContent>
</Item>
<Item variant="muted" className="bg-green-50">
<Item variant="muted" className="bg-green-50 dark:bg-green-950/30">
<ItemMedia variant="icon">
<CheckCircle2 />
</ItemMedia>
@@ -211,6 +213,7 @@ function TasksPage() {
onToggle={handleCheckboxToggle}
onEdit={setEditTask}
onDelete={(id) => deleteTask.mutate({ id })}
onClick={setViewTask}
/>
))
)}
@@ -222,6 +225,13 @@ function TasksPage() {
open={!!editTask}
onOpenChange={(open: boolean) => { if (!open) setEditTask(null); }}
/>
<TaskDetailDialog
task={viewTask}
open={!!viewTask}
onOpenChange={(open) => { if (!open) setViewTask(null); }}
onEdit={(task) => { setViewTask(null); setEditTask(task); }}
onDelete={(id) => { deleteTask.mutate({ id }); setViewTask(null); }}
/>
</div>
);
}