feat: Add NoteForm, ProjectForm, and ProjectTaskForm components

- Implemented NoteForm for adding notes to projects.
- Created ProjectForm for managing project details with contract selection.
- Developed ProjectTaskForm for adding tasks to projects, supporting both templates and custom tasks.

feat: Add ProjectTasksSection component

- Introduced ProjectTasksSection to display and manage tasks for a specific project.
- Includes functionality for adding, updating, and deleting tasks.

feat: Create TaskTemplateForm for managing task templates

- Added TaskTemplateForm for creating new task templates with required wait days.

feat: Implement UI components

- Created reusable UI components: Badge, Button, Card, Input, Loading, Navigation.
- Enhanced user experience with consistent styling and functionality.

feat: Set up database and queries

- Initialized SQLite database with tables for contracts, projects, tasks, project tasks, and notes.
- Implemented queries for managing contracts, projects, tasks, and notes.

chore: Add error handling and loading states

- Improved error handling in forms and data fetching.
- Added loading states for better user feedback during data operations.
This commit is contained in:
Chop
2025-06-02 22:07:05 +02:00
parent aa1eb99ce9
commit d0586f2876
43 changed files with 3272 additions and 137 deletions

View File

14
src/lib/queries/notes.js Normal file
View File

@@ -0,0 +1,14 @@
import db from "../db.js";
export function getNotesByProjectId(project_id) {
return db
.prepare(`SELECT * FROM notes WHERE project_id = ? ORDER BY note_date DESC`)
.all(project_id);
}
export function addNoteToProject(project_id, note) {
db.prepare(`INSERT INTO notes (project_id, note) VALUES (?, ?)`).run(
project_id,
note
);
}

105
src/lib/queries/projects.js Normal file
View File

@@ -0,0 +1,105 @@
import db from "../db.js";
export function getAllProjects() {
return db.prepare("SELECT * FROM projects ORDER BY finish_date DESC").all();
}
export function getProjectById(id) {
return db.prepare("SELECT * FROM projects WHERE project_id = ?").get(id);
}
export function createProject(data) {
// 1. Get the max project_number under this contract
const existing = db
.prepare(
`
SELECT MAX(project_number) as max_number
FROM projects
WHERE contract_id = ?
`
)
.get(data.contract_id);
const nextNumber = (existing.max_number || 0) + 1;
const stmt = db.prepare(`
INSERT INTO projects (
contract_id, project_name, project_number, address, plot, district, unit, city, investment_number, finish_date,
wp, contact, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`);
stmt.run(
data.contract_id,
data.project_name,
parseInt(nextNumber),
data.address,
data.plot,
data.district,
data.unit,
data.city,
data.investment_number,
data.finish_date,
data.wp,
data.contact,
data.notes
);
}
export function updateProject(id, data) {
const stmt = db.prepare(`
UPDATE projects SET
contract_id = ?, project_name = ?, project_number = ?, address = ?, plot = ?, district = ?, unit = ?, city = ?,
investment_number = ?, finish_date = ?, wp = ?, contact = ?, notes = ?
WHERE project_id = ?
`);
stmt.run(
data.contract_id,
data.project_name,
data.project_number,
data.address,
data.plot,
data.district,
data.unit,
data.city,
data.investment_number,
data.finish_date,
data.wp,
data.contact,
data.notes,
id
);
}
export function deleteProject(id) {
db.prepare("DELETE FROM projects WHERE project_id = ?").run(id);
}
export function getProjectWithContract(id) {
return db
.prepare(
`
SELECT
p.*,
c.contract_number,
c.contract_name,
c.customer,
c.investor
FROM projects p
LEFT JOIN contracts c ON p.contract_id = c.contract_id
WHERE p.project_id = ?
`
)
.get(id);
}
export function getNotesForProject(projectId) {
return db
.prepare(
`
SELECT * FROM notes
WHERE project_id = ?
ORDER BY note_date DESC
`
)
.all(projectId);
}

76
src/lib/queries/tasks.js Normal file
View File

@@ -0,0 +1,76 @@
import db from "../db.js";
// Get all task templates (for dropdown selection)
export function getAllTaskTemplates() {
return db
.prepare("SELECT * FROM tasks WHERE is_standard = 1 ORDER BY name ASC")
.all();
}
// Get project tasks for a specific project
export function getProjectTasks(projectId) {
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
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
WHERE pt.project_id = ?
ORDER BY pt.date_added DESC
`
)
.all(projectId);
}
// Create a new project task
export function createProjectTask(data) {
if (data.task_template_id) {
// Creating from template
const stmt = db.prepare(`
INSERT INTO project_tasks (project_id, task_template_id, status, priority)
VALUES (?, ?, ?, ?)
`);
return stmt.run(
data.project_id,
data.task_template_id,
data.status || "pending",
data.priority || "normal"
);
} else {
// Creating custom task
const stmt = db.prepare(`
INSERT INTO project_tasks (project_id, custom_task_name, custom_max_wait_days, status, priority)
VALUES (?, ?, ?, ?, ?)
`);
return stmt.run(
data.project_id,
data.custom_task_name,
data.custom_max_wait_days || 0,
data.status || "pending",
data.priority || "normal"
);
}
}
// Update project task status
export function updateProjectTaskStatus(taskId, status) {
const stmt = db.prepare(`
UPDATE project_tasks
SET status = ?
WHERE id = ?
`);
return stmt.run(status, taskId);
}
// Delete a project task
export function deleteProjectTask(taskId) {
const stmt = db.prepare("DELETE FROM project_tasks WHERE id = ?");
return stmt.run(taskId);
}