From 6cacfe33f934a4a1aacc030b7b95eb3d7829a084 Mon Sep 17 00:00:00 2001 From: Hammer Date: Wed, 28 Jan 2026 19:02:55 +0000 Subject: [PATCH] fix: parse ISO dueDate to YYYY-MM-DD for date input display --- dist/index.html | 2 +- src/components/TaskDetail.tsx | 4 +-- src/pages/Project.tsx | 48 ++++++++++++++++++++++++++++++++--- src/stores/tasks.ts | 16 ++++++++++++ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/dist/index.html b/dist/index.html index e458783..46fbcfd 100644 --- a/dist/index.html +++ b/dist/index.html @@ -6,7 +6,7 @@ Todo App - + diff --git a/src/components/TaskDetail.tsx b/src/components/TaskDetail.tsx index 5981ac3..f07b2fd 100644 --- a/src/components/TaskDetail.tsx +++ b/src/components/TaskDetail.tsx @@ -17,7 +17,7 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { const { updateTask, deleteTask, toggleComplete, projects, users, fetchUsers } = useTasksStore(); const [title, setTitle] = useState(task.title); const [description, setDescription] = useState(task.description || ''); - const [dueDate, setDueDate] = useState(task.dueDate || ''); + const [dueDate, setDueDate] = useState(task.dueDate ? task.dueDate.slice(0, 10) : ''); const [priority, setPriority] = useState(task.priority); const [assigneeId, setAssigneeId] = useState(task.assigneeId || ''); const [projectId, setProjectId] = useState(task.projectId || ''); @@ -30,7 +30,7 @@ export function TaskDetail({ task, onClose }: TaskDetailProps) { useEffect(() => { setTitle(task.title); setDescription(task.description || ''); - setDueDate(task.dueDate || ''); + setDueDate(task.dueDate ? task.dueDate.slice(0, 10) : ''); setPriority(task.priority); setAssigneeId(task.assigneeId || ''); setProjectId(task.projectId || ''); diff --git a/src/pages/Project.tsx b/src/pages/Project.tsx index 512d618..bf8f37e 100644 --- a/src/pages/Project.tsx +++ b/src/pages/Project.tsx @@ -1,6 +1,6 @@ -import { useEffect, useState } from 'react'; +import { useEffect, useState, useRef } from 'react'; import { useParams, useNavigate, useLocation } from 'react-router-dom'; -import { LayoutList, LayoutGrid, Plus } from 'lucide-react'; +import { LayoutList, LayoutGrid, Plus, Pencil, Trash2, AlertCircle } from 'lucide-react'; import { cn } from '@/lib/utils'; import { useTasksStore } from '@/stores/tasks'; import { TaskItem } from '@/components/TaskItem'; @@ -14,9 +14,14 @@ export function ProjectPage() { const { id } = useParams<{ id: string }>(); const location = useLocation(); const navigate = useNavigate(); - const { tasks, completedTasks, isLoading, fetchTasks, fetchCompletedTasks, setSelectedTask } = useTasksStore(); + const { tasks, completedTasks, isLoading, fetchTasks, fetchCompletedTasks, setSelectedTask, updateProject, deleteProject, fetchProjects } = useTasksStore(); const [project, setProject] = useState(null); const [sections, setSections] = useState([]); + const [isEditing, setIsEditing] = useState(false); + const [editName, setEditName] = useState(''); + const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); + const [isDeleting, setIsDeleting] = useState(false); + const nameInputRef = useRef(null); const isBoardView = location.pathname.endsWith('/board'); @@ -30,6 +35,43 @@ export function ProjectPage() { }).catch(console.error); }, [id]); + useEffect(() => { + if (isEditing && nameInputRef.current) { + nameInputRef.current.focus(); + nameInputRef.current.select(); + } + }, [isEditing]); + + const handleStartRename = () => { + if (!project) return; + setEditName(project.name); + setIsEditing(true); + }; + + const handleSaveRename = async () => { + if (!project || !id) return; + const trimmed = editName.trim(); + if (trimmed && trimmed !== project.name) { + await updateProject(id, { name: trimmed }); + setProject({ ...project, name: trimmed }); + } + setIsEditing(false); + }; + + const handleDeleteProject = async () => { + if (!id) return; + setIsDeleting(true); + try { + await deleteProject(id); + await fetchProjects(); + navigate('/inbox'); + } catch (error) { + console.error('Failed to delete project:', error); + setIsDeleting(false); + setShowDeleteConfirm(false); + } + }; + if (!project) { return (
diff --git a/src/stores/tasks.ts b/src/stores/tasks.ts index c44fa78..6a07233 100644 --- a/src/stores/tasks.ts +++ b/src/stores/tasks.ts @@ -27,6 +27,8 @@ interface TasksState { deleteTask: (id: string) => Promise; toggleComplete: (id: string) => Promise; createProject: (data: { name: string; color?: string; icon?: string }) => Promise; + updateProject: (id: string, data: Partial) => Promise; + deleteProject: (id: string) => Promise; setSelectedTask: (task: Task | null) => void; setActiveProject: (projectId: string | null) => void; @@ -121,6 +123,20 @@ export const useTasksStore = create((set, get) => ({ return project; }, + updateProject: async (id, data) => { + const updated = await api.updateProject(id, data); + set((state) => ({ + projects: state.projects.map((p) => (p.id === id ? { ...p, ...updated } : p)), + })); + }, + + deleteProject: async (id) => { + await api.deleteProject(id); + set((state) => ({ + projects: state.projects.filter((p) => p.id !== id), + })); + }, + toggleComplete: async (id) => { const task = get().tasks.find((t) => t.id === id) || get().completedTasks.find((t) => t.id === id); if (!task) return;