From a6ef325813e7f824e915b1975c6f3681fef5bb96 Mon Sep 17 00:00:00 2001 From: chop Date: Tue, 7 Oct 2025 22:22:10 +0200 Subject: [PATCH] feat: add task_category field to tasks with validation and update related forms --- src/app/api/tasks/[id]/route.js | 10 +++++++--- src/app/api/tasks/route.js | 12 ++++++++---- src/app/task-sets/new/page.js | 4 ++-- src/app/tasks/templates/page.js | 22 +++++++++++++++++++--- src/components/TaskTemplateForm.js | 18 ++++++++++++++++++ src/lib/init-db.js | 19 ++++++++++++++++++- 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/src/app/api/tasks/[id]/route.js b/src/app/api/tasks/[id]/route.js index 92009e4..a02e708 100644 --- a/src/app/api/tasks/[id]/route.js +++ b/src/app/api/tasks/[id]/route.js @@ -30,19 +30,23 @@ async function getTaskHandler(req, { params }) { async function updateTaskHandler(req, { params }) { const { id } = await params; try { - const { name, max_wait_days, description } = await req.json(); + const { name, max_wait_days, description, task_category } = await req.json(); if (!name) { return NextResponse.json({ error: "Name is required" }, { status: 400 }); } + if (task_category && !['design', 'construction'].includes(task_category)) { + return NextResponse.json({ error: "Invalid task_category (must be design or construction)" }, { status: 400 }); + } + const result = db .prepare( `UPDATE tasks - SET name = ?, max_wait_days = ?, description = ? + SET name = ?, max_wait_days = ?, description = ?, task_category = ? WHERE task_id = ? AND is_standard = 1` ) - .run(name, max_wait_days || 0, description || null, id); + .run(name, max_wait_days || 0, description || null, task_category, id); if (result.changes === 0) { return NextResponse.json( diff --git a/src/app/api/tasks/route.js b/src/app/api/tasks/route.js index 24d63bc..4403cbc 100644 --- a/src/app/api/tasks/route.js +++ b/src/app/api/tasks/route.js @@ -5,18 +5,22 @@ import { getAllTaskTemplates } from "@/lib/queries/tasks"; // POST: create new template async function createTaskHandler(req) { - const { name, max_wait_days, description } = await req.json(); + const { name, max_wait_days, description, task_category } = await req.json(); if (!name) { return NextResponse.json({ error: "Name is required" }, { status: 400 }); } + if (!task_category || !['design', 'construction'].includes(task_category)) { + return NextResponse.json({ error: "Valid task_category is required (design or construction)" }, { status: 400 }); + } + db.prepare( ` - INSERT INTO tasks (name, max_wait_days, description, is_standard) - VALUES (?, ?, ?, 1) + INSERT INTO tasks (name, max_wait_days, description, is_standard, task_category) + VALUES (?, ?, ?, 1, ?) ` - ).run(name, max_wait_days || 0, description || null); + ).run(name, max_wait_days || 0, description || null, task_category); return NextResponse.json({ success: true }); } diff --git a/src/app/task-sets/new/page.js b/src/app/task-sets/new/page.js index 6c6e5a7..e2c167f 100644 --- a/src/app/task-sets/new/page.js +++ b/src/app/task-sets/new/page.js @@ -16,7 +16,7 @@ export default function NewTaskSetPage() { const [formData, setFormData] = useState({ name: "", description: "", - project_type: "design", + task_category: "design", selectedTemplates: [] }); const [isSubmitting, setIsSubmitting] = useState(false); @@ -61,7 +61,7 @@ export default function NewTaskSetPage() { body: JSON.stringify({ name: formData.name.trim(), description: formData.description.trim(), - project_type: formData.project_type + task_category: formData.task_category }) }); diff --git a/src/app/tasks/templates/page.js b/src/app/tasks/templates/page.js index 24eeaca..8ec008f 100644 --- a/src/app/tasks/templates/page.js +++ b/src/app/tasks/templates/page.js @@ -34,6 +34,19 @@ export default function TaskTemplatesPage() { fetchTemplates(); }, []); + const getTaskCategoryBadge = (taskCategory) => { + const colors = { + design: "bg-blue-100 text-blue-800", + construction: "bg-green-100 text-green-800" + }; + + return ( + + {taskCategory === "design" ? "Projektowe" : taskCategory === "construction" ? "Budowlane" : taskCategory} + + ); + }; + if (loading) { return ( @@ -170,9 +183,12 @@ export default function TaskTemplatesPage() {

{template.name}

- - {template.max_wait_days} {t('common.days')} - +
+ + {template.max_wait_days} {t('common.days')} + + {getTaskCategoryBadge(template.task_category)} +
{template.description && (

diff --git a/src/components/TaskTemplateForm.js b/src/components/TaskTemplateForm.js index 3f3b75d..d97ef10 100644 --- a/src/components/TaskTemplateForm.js +++ b/src/components/TaskTemplateForm.js @@ -14,6 +14,7 @@ export default function TaskTemplateForm({ const [name, setName] = useState(""); const [max_wait_days, setRequiredWaitDays] = useState(""); const [description, setDescription] = useState(""); + const [task_category, setTaskCategory] = useState("design"); const [loading, setLoading] = useState(false); const [isEditing, setIsEditing] = useState(false); const router = useRouter(); @@ -26,6 +27,7 @@ export default function TaskTemplateForm({ setName(initialData.name || ""); setRequiredWaitDays(initialData.max_wait_days?.toString() || ""); setDescription(initialData.description || ""); + setTaskCategory(initialData.task_category || "design"); } } }, [templateId, initialData]); @@ -45,6 +47,7 @@ export default function TaskTemplateForm({ name, max_wait_days: parseInt(max_wait_days, 10) || 0, description: description || null, + task_category, }), }); @@ -78,6 +81,21 @@ export default function TaskTemplateForm({ /> +

+ + +
+