From f9145f6a467d090effbb672382a253f2241473f4 Mon Sep 17 00:00:00 2001 From: Hammer Date: Wed, 28 Jan 2026 19:03:44 +0000 Subject: [PATCH] feat: add project rename/delete and section selector in task detail --- dist/index.html | 4 +-- src/components/TaskDetail.tsx | 54 ++++++++++++++++++++++++++++-- src/pages/Project.tsx | 63 ++++++++++++++++++++++++++++++++++- 3 files changed, 115 insertions(+), 6 deletions(-) diff --git a/dist/index.html b/dist/index.html index 46fbcfd..c43abbb 100644 --- a/dist/index.html +++ b/dist/index.html @@ -6,8 +6,8 @@ Todo App - - + +
diff --git a/src/components/TaskDetail.tsx b/src/components/TaskDetail.tsx index f07b2fd..c9a8b52 100644 --- a/src/components/TaskDetail.tsx +++ b/src/components/TaskDetail.tsx @@ -1,9 +1,9 @@ import { useState, useEffect, useRef } from 'react'; import { X, Check, Trash2, Calendar, Flag, User, FolderOpen, - Tag, MessageSquare, ChevronRight, AlertCircle + Tag, MessageSquare, ChevronRight, AlertCircle, Layers } from 'lucide-react'; -import type { Task, Priority, Comment } from '@/types'; +import type { Task, Priority, Comment, Section } from '@/types'; import { cn, formatDate, getPriorityColor, getPriorityLabel } from '@/lib/utils'; import { useTasksStore } from '@/stores/tasks'; import { api } from '@/lib/api'; @@ -21,6 +21,8 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { const [priority, setPriority] = useState(task.priority); const [assigneeId, setAssigneeId] = useState(task.assigneeId || ''); const [projectId, setProjectId] = useState(task.projectId || ''); + const [sectionId, setSectionId] = useState(task.sectionId || ''); + const [availableSections, setAvailableSections] = useState([]); const [comments, setComments] = useState([]); const [isDeleting, setIsDeleting] = useState(false); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); @@ -34,6 +36,7 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { setPriority(task.priority); setAssigneeId(task.assigneeId || ''); setProjectId(task.projectId || ''); + setSectionId(task.sectionId || ''); }, [task]); useEffect(() => { @@ -42,6 +45,22 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { } }, []); + // Load sections for the current project + useEffect(() => { + if (projectId) { + const proj = projects.find(p => p.id === projectId); + if (proj?.sections) { + setAvailableSections(proj.sections); + } else { + api.getProject(projectId).then((p) => { + setAvailableSections(p.sections || []); + }).catch(() => setAvailableSections([])); + } + } else { + setAvailableSections([]); + } + }, [projectId, projects]); + useEffect(() => { api.getComments(task.id).then(setComments).catch(() => setComments([])); }, [task.id]); @@ -76,7 +95,13 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { const handleProjectChange = (value: string) => { setProjectId(value); - updateTask(task.id, { projectId: value || undefined }); + setSectionId(''); + updateTask(task.id, { projectId: value || undefined, sectionId: undefined }); + }; + + const handleSectionChange = (value: string) => { + setSectionId(value); + updateTask(task.id, { sectionId: value || undefined }); }; const handleDelete = async () => { @@ -210,6 +235,29 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { + {/* Section */} + {projectId && availableSections.length > 0 && ( +
+ + Section + +
+ )} + {/* Due Date */}
diff --git a/src/pages/Project.tsx b/src/pages/Project.tsx index bf8f37e..241f883 100644 --- a/src/pages/Project.tsx +++ b/src/pages/Project.tsx @@ -104,7 +104,68 @@ export function ProjectPage() { className="w-4 h-4 rounded" style={{ backgroundColor: project.color }} /> -

{project.name}

+ {isEditing ? ( + setEditName(e.target.value)} + onBlur={handleSaveRename} + onKeyDown={(e) => { + if (e.key === 'Enter') handleSaveRename(); + if (e.key === 'Escape') setIsEditing(false); + }} + className="text-2xl font-bold text-gray-900 border-b-2 border-blue-400 outline-none bg-transparent" + /> + ) : ( +

+ {project.name} +

+ )} + {!isEditing && !project.isInbox && ( +
+ + {showDeleteConfirm ? ( +
+ + + Delete? + + + +
+ ) : ( + + )} +
+ )}