From ab8cc0a6a14dc0e128c309d43286cfc45635ad43 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 22 Feb 2026 17:56:39 -0600 Subject: [PATCH] fixed Signed-off-by: Max --- src/app/api/sprints/route.ts | 2 +- src/app/api/tasks/route.ts | 2 +- src/app/page.tsx | 10 ++++++++- src/app/tasks/[taskId]/page.tsx | 40 ++++++++++++++++++++++++++++++++- src/components/BacklogView.tsx | 4 ++-- src/stores/useTaskStore.ts | 28 ++++++++++++++++++++++- 6 files changed, 79 insertions(+), 7 deletions(-) diff --git a/src/app/api/sprints/route.ts b/src/app/api/sprints/route.ts index 0f9aa42..d7b96d3 100644 --- a/src/app/api/sprints/route.ts +++ b/src/app/api/sprints/route.ts @@ -7,7 +7,7 @@ export const runtime = "nodejs"; // Sprint dates are stored as SQL DATE values (YYYY-MM-DD). We accept either // date-only or ISO datetime inputs and normalize to the date prefix. const DATE_PREFIX_PATTERN = /^(\d{4}-\d{2}-\d{2})/; -const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; +const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; const SPRINT_STATUSES = ["planning", "active", "completed"] as const; type SprintStatus = (typeof SPRINT_STATUSES)[number]; diff --git a/src/app/api/tasks/route.ts b/src/app/api/tasks/route.ts index be653f1..1b001ac 100644 --- a/src/app/api/tasks/route.ts +++ b/src/app/api/tasks/route.ts @@ -61,7 +61,7 @@ const TASK_TYPES: Task["type"][] = ["idea", "task", "bug", "research", "plan"]; const TASK_STATUSES: Task["status"][] = ["open", "todo", "blocked", "in-progress", "review", "validate", "archived", "canceled", "done"]; const TASK_PRIORITIES: Task["priority"][] = ["low", "medium", "high", "urgent"]; const SPRINT_STATUSES: Sprint["status"][] = ["planning", "active", "completed"]; -const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; +const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; // Optimized field selection - only fetch fields needed for board display // Full task details (description, comments, attachments) fetched lazily diff --git a/src/app/page.tsx b/src/app/page.tsx index 1aa10da..21e6320 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -38,6 +38,7 @@ import { import { useTaskStore, Task, TaskType, TaskStatus, Priority, TaskAttachment, type CommentAuthor } from "@/stores/useTaskStore" import { BacklogSkeleton, SearchSkeleton } from "@/components/LoadingSkeletons" import { Plus, MessageSquare, Calendar, Trash2, X, LayoutGrid, ListTodo, GripVertical, Paperclip, Download, Search, Archive } from "lucide-react" +import { toast } from "sonner" // Dynamic imports for heavy view components - only load when needed const BacklogView = dynamic(() => import("@/components/BacklogView").then(mod => mod.BacklogView), { @@ -830,7 +831,14 @@ export default function Home() { if (newTask.title?.trim()) { // If a specific sprint is selected, use that sprint's project const selectedSprint = newTask.sprintId ? sprints.find(s => s.id === newTask.sprintId) : null - const targetProjectId = selectedSprint?.projectId || selectedProjectId || projects[0]?.id || '2' + const targetProjectId = selectedSprint?.projectId || selectedProjectId || projects[0]?.id + if (!targetProjectId) { + toast.error("Cannot create task", { + description: "No project is available. Create or select a project first.", + duration: 5000, + }) + return + } const taskToCreate: Omit = { title: newTask.title.trim(), diff --git a/src/app/tasks/[taskId]/page.tsx b/src/app/tasks/[taskId]/page.tsx index c0df0df..bf2a7c5 100644 --- a/src/app/tasks/[taskId]/page.tsx +++ b/src/app/tasks/[taskId]/page.tsx @@ -227,6 +227,7 @@ export default function TaskDetailPage() { const { tasks, + projects, sprints, currentUser, updateTask, @@ -355,9 +356,10 @@ export default function TaskDetailPage() { const sortedSprints = useMemo( () => sprints + .filter((sprint) => sprint.projectId === editedTask?.projectId) .slice() .sort((a, b) => parseSprintStart(a.startDate).getTime() - parseSprintStart(b.startDate).getTime()), - [sprints] + [sprints, editedTask?.projectId] ) const handleAttachmentUpload = async (event: ChangeEvent) => { @@ -459,8 +461,28 @@ export default function TaskDetailPage() { }) } + const setEditedTaskProject = (projectId: string) => { + if (!editedTask) return + + const sprintStillMatchesProject = + !editedTask.sprintId || sprints.some((sprint) => sprint.id === editedTask.sprintId && sprint.projectId === projectId) + + setEditedTask({ + ...editedTask, + projectId, + sprintId: sprintStillMatchesProject ? editedTask.sprintId : undefined, + }) + } + const handleSave = async () => { if (!editedTask) return + if (!editedTask.projectId) { + toast.error("Project is required", { + description: "Select a project before saving this task.", + duration: 5000, + }) + return + } setIsSaving(true) setSaveSuccess(false) @@ -777,6 +799,22 @@ export default function TaskDetailPage() { +
+ + +
+