feat: Implement project search functionality and task management features

- Added search functionality to the Project List page, allowing users to filter projects by name, WP, plot, or investment number.
- Created a new Project Tasks page to manage tasks across all projects, including filtering by status and priority.
- Implemented task status updates and deletion functionality.
- Added a new Task Template Edit page for modifying existing task templates.
- Enhanced Task Template Form to include a description field and loading state during submission.
- Updated UI components for better user experience, including badges for task status and priority.
- Introduced new database queries for managing contracts and projects, including fetching tasks related to projects.
- Added migrations to the database for new columns and improved data handling.
This commit is contained in:
Chop
2025-06-02 23:21:04 +02:00
parent b06aad72b8
commit 35569846bc
24 changed files with 2019 additions and 169 deletions

View File

@@ -0,0 +1,15 @@
import { getAllProjectTasks } from "@/lib/queries/tasks";
import { NextResponse } from "next/server";
// GET: Get all project tasks across all projects
export async function GET() {
try {
const tasks = getAllProjectTasks();
return NextResponse.json(tasks);
} catch (error) {
return NextResponse.json(
{ error: "Failed to fetch all project tasks" },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,59 @@
import db from "@/lib/db";
import { NextResponse } from "next/server";
export async function GET(req, { params }) {
const { id } = await params;
const contract = db
.prepare(
`
SELECT * FROM contracts
WHERE contract_id = ?
`
)
.get(id);
if (!contract) {
return NextResponse.json({ error: "Contract not found" }, { status: 404 });
}
return NextResponse.json(contract);
}
export async function DELETE(req, { params }) {
const { id } = params;
try {
// Check if there are any projects linked to this contract
const linkedProjects = db
.prepare("SELECT COUNT(*) as count FROM projects WHERE contract_id = ?")
.get(id);
if (linkedProjects.count > 0) {
return NextResponse.json(
{ error: "Nie można usunąć umowy z przypisanymi projektami" },
{ status: 400 }
);
}
// Delete the contract
const result = db
.prepare("DELETE FROM contracts WHERE contract_id = ?")
.run(id);
if (result.changes === 0) {
return NextResponse.json(
{ error: "Contract not found" },
{ status: 404 }
);
}
return NextResponse.json({ success: true });
} catch (error) {
console.error("Error deleting contract:", error);
return NextResponse.json(
{ error: "Internal server error" },
{ status: 500 }
);
}
}

View File

@@ -5,8 +5,17 @@ export async function GET() {
const contracts = db
.prepare(
`
SELECT contract_id, contract_number, contract_name FROM contracts
`
SELECT
contract_id,
contract_number,
contract_name,
customer,
investor,
date_signed,
finish_date
FROM contracts
ORDER BY contract_number
`
)
.all();
return NextResponse.json(contracts);

View File

@@ -5,8 +5,11 @@ import { NextResponse } from "next/server";
// Make sure the DB is initialized before queries run
initializeDatabase();
export async function GET() {
const projects = getAllProjects();
export async function GET(req) {
const { searchParams } = new URL(req.url);
const contractId = searchParams.get("contract_id");
const projects = getAllProjects(contractId);
return NextResponse.json(projects);
}

View File

@@ -0,0 +1,81 @@
import db from "@/lib/db";
import { NextResponse } from "next/server";
// GET: Get a specific task template
export async function GET(req, { params }) {
try {
const template = db
.prepare("SELECT * FROM tasks WHERE task_id = ? AND is_standard = 1")
.get(params.id);
if (!template) {
return NextResponse.json(
{ error: "Task template not found" },
{ status: 404 }
);
}
return NextResponse.json(template);
} catch (error) {
return NextResponse.json(
{ error: "Failed to fetch task template" },
{ status: 500 }
);
}
}
// PUT: Update a task template
export async function PUT(req, { params }) {
try {
const { name, max_wait_days, description } = await req.json();
if (!name) {
return NextResponse.json({ error: "Name is required" }, { status: 400 });
}
const result = db
.prepare(
`UPDATE tasks
SET name = ?, max_wait_days = ?, description = ?
WHERE task_id = ? AND is_standard = 1`
)
.run(name, max_wait_days || 0, description || null, params.id);
if (result.changes === 0) {
return NextResponse.json(
{ error: "Task template not found" },
{ status: 404 }
);
}
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: "Failed to update task template" },
{ status: 500 }
);
}
}
// DELETE: Delete a task template
export async function DELETE(req, { params }) {
try {
const result = db
.prepare("DELETE FROM tasks WHERE task_id = ? AND is_standard = 1")
.run(params.id);
if (result.changes === 0) {
return NextResponse.json(
{ error: "Task template not found" },
{ status: 404 }
);
}
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: "Failed to delete task template" },
{ status: 500 }
);
}
}

View File

@@ -3,7 +3,7 @@ import { NextResponse } from "next/server";
// POST: create new template
export async function POST(req) {
const { name, max_wait_days } = await req.json();
const { name, max_wait_days, description } = await req.json();
if (!name) {
return NextResponse.json({ error: "Name is required" }, { status: 400 });
@@ -11,10 +11,10 @@ export async function POST(req) {
db.prepare(
`
INSERT INTO tasks (name, max_wait_days, is_standard)
VALUES (?, ?, 1)
INSERT INTO tasks (name, max_wait_days, description, is_standard)
VALUES (?, ?, ?, 1)
`
).run(name, max_wait_days || 0);
).run(name, max_wait_days || 0, description || null);
return NextResponse.json({ success: true });
}