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,57 @@
import db from "../db";
export function getAllContracts() {
return db
.prepare(
`
SELECT
contract_id,
contract_number,
contract_name,
customer,
investor,
date_signed,
finish_date
FROM contracts
ORDER BY contract_number
`
)
.all();
}
export function getContractById(id) {
return db
.prepare(
`
SELECT * FROM contracts
WHERE contract_id = ?
`
)
.get(id);
}
export function deleteContract(id) {
db.prepare("DELETE FROM contracts WHERE contract_id = ?").run(id);
}
export function getContractWithProjects(id) {
const contract = getContractById(id);
if (!contract) return null;
const projects = db
.prepare(
`
SELECT
project_id,
project_name,
project_number,
finish_date
FROM projects
WHERE contract_id = ?
ORDER BY project_name
`
)
.all(id);
return { ...contract, projects };
}

View File

@@ -1,6 +1,13 @@
import db from "../db.js";
export function getAllProjects() {
export function getAllProjects(contractId = null) {
if (contractId) {
return db
.prepare(
"SELECT * FROM projects WHERE contract_id = ? ORDER BY finish_date DESC"
)
.all(contractId);
}
return db.prepare("SELECT * FROM projects ORDER BY finish_date DESC").all();
}
@@ -9,18 +16,28 @@ export function getProjectById(id) {
}
export function createProject(data) {
// 1. Get the max project_number under this contract
const existing = db
// 1. Get the contract number and count existing projects
const contractInfo = db
.prepare(
`
SELECT MAX(project_number) as max_number
FROM projects
WHERE contract_id = ?
SELECT
c.contract_number,
COUNT(p.project_id) as project_count
FROM contracts c
LEFT JOIN projects p ON c.contract_id = p.contract_id
WHERE c.contract_id = ?
GROUP BY c.contract_id, c.contract_number
`
)
.get(data.contract_id);
const nextNumber = (existing.max_number || 0) + 1;
if (!contractInfo) {
throw new Error("Contract not found");
}
// 2. Generate sequential number and project number
const sequentialNumber = (contractInfo.project_count || 0) + 1;
const projectNumber = `${sequentialNumber}/${contractInfo.contract_number}`;
const stmt = db.prepare(`
INSERT INTO projects (
@@ -31,7 +48,7 @@ export function createProject(data) {
stmt.run(
data.contract_id,
data.project_name,
parseInt(nextNumber),
projectNumber,
data.address,
data.plot,
data.district,

View File

@@ -7,6 +7,32 @@ export function getAllTaskTemplates() {
.all();
}
// Get all project tasks across all projects
export function getAllProjectTasks() {
return db
.prepare(
`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name,
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
CASE
WHEN pt.task_template_id IS NOT NULL THEN 'template'
ELSE 'custom'
END as task_type,
p.project_name,
p.wp,
p.plot,
p.finish_date
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
LEFT JOIN projects p ON pt.project_id = p.project_id
ORDER BY pt.date_added DESC
`
)
.all();
}
// Get project tasks for a specific project
export function getProjectTasks(projectId) {
return db