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

@@ -0,0 +1,39 @@
import db from "@/lib/db";
import { NextResponse } from "next/server";
export async function GET() {
const contracts = db
.prepare(
`
SELECT contract_id, contract_number, contract_name FROM contracts
`
)
.all();
return NextResponse.json(contracts);
}
export async function POST(req) {
const data = await req.json();
db.prepare(
`
INSERT INTO contracts (
contract_number,
contract_name,
customer_contract_number,
customer,
investor,
date_signed,
finish_date
) VALUES (?, ?, ?, ?, ?, ?, ?)
`
).run(
data.contract_number,
data.contract_name,
data.customer_contract_number,
data.customer,
data.investor,
data.date_signed,
data.finish_date
);
return NextResponse.json({ success: true });
}

View File

@@ -0,0 +1,44 @@
import db from "@/lib/db";
import { NextResponse } from "next/server";
export async function POST(req) {
const { project_id, task_id, note } = await req.json();
if (!note || (!project_id && !task_id)) {
return NextResponse.json({ error: "Missing fields" }, { status: 400 });
}
db.prepare(
`
INSERT INTO notes (project_id, task_id, note)
VALUES (?, ?, ?)
`
).run(project_id || null, task_id || null, note);
return NextResponse.json({ success: true });
}
export async function DELETE(_, { params }) {
const { id } = params;
db.prepare("DELETE FROM notes WHERE note_id = ?").run(id);
return NextResponse.json({ success: true });
}
export async function PUT(req, { params }) {
const noteId = params.id;
const { note } = await req.json();
if (!note || !noteId) {
return NextResponse.json({ error: "Missing note or ID" }, { status: 400 });
}
db.prepare(
`
UPDATE notes SET note = ? WHERE note_id = ?
`
).run(note, noteId);
return NextResponse.json({ success: true });
}

View File

@@ -0,0 +1,40 @@
import {
updateProjectTaskStatus,
deleteProjectTask,
} from "@/lib/queries/tasks";
import { NextResponse } from "next/server";
// PATCH: Update project task status
export async function PATCH(req, { params }) {
try {
const { status } = await req.json();
if (!status) {
return NextResponse.json(
{ error: "Status is required" },
{ status: 400 }
);
}
updateProjectTaskStatus(params.id, status);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: "Failed to update project task" },
{ status: 500 }
);
}
}
// DELETE: Delete a project task
export async function DELETE(req, { params }) {
try {
deleteProjectTask(params.id);
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: "Failed to delete project task" },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,52 @@
import {
getAllTaskTemplates,
getProjectTasks,
createProjectTask,
} from "@/lib/queries/tasks";
import { NextResponse } from "next/server";
// GET: Get all project tasks or task templates based on query params
export async function GET(req) {
const { searchParams } = new URL(req.url);
const projectId = searchParams.get("project_id");
if (projectId) {
// Get tasks for a specific project
const tasks = getProjectTasks(projectId);
return NextResponse.json(tasks);
} else {
// Default: return all task templates
const templates = getAllTaskTemplates();
return NextResponse.json(templates);
}
}
// POST: Create a new project task
export async function POST(req) {
try {
const data = await req.json();
if (!data.project_id) {
return NextResponse.json(
{ error: "project_id is required" },
{ status: 400 }
);
}
// Check if it's a template task or custom task
if (!data.task_template_id && !data.custom_task_name) {
return NextResponse.json(
{ error: "Either task_template_id or custom_task_name is required" },
{ status: 400 }
);
}
const result = createProjectTask(data);
return NextResponse.json({ success: true, id: result.lastInsertRowid });
} catch (error) {
return NextResponse.json(
{ error: "Failed to create project task" },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,22 @@
import {
getProjectById,
updateProject,
deleteProject,
} from "@/lib/queries/projects";
import { NextResponse } from "next/server";
export async function GET(_, { params }) {
const project = getProjectById(params.id);
return NextResponse.json(project);
}
export async function PUT(req, { params }) {
const data = await req.json();
updateProject(params.id, data);
return NextResponse.json({ success: true });
}
export async function DELETE(_, { params }) {
deleteProject(params.id);
return NextResponse.json({ success: true });
}

View File

@@ -0,0 +1,17 @@
import { getAllProjects, createProject } from "@/lib/queries/projects";
import initializeDatabase from "@/lib/init-db";
import { NextResponse } from "next/server";
// Make sure the DB is initialized before queries run
initializeDatabase();
export async function GET() {
const projects = getAllProjects();
return NextResponse.json(projects);
}
export async function POST(req) {
const data = await req.json();
createProject(data);
return NextResponse.json({ success: true });
}

View File

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

View File

@@ -0,0 +1,8 @@
import { getAllTaskTemplates } from "@/lib/queries/tasks";
import { NextResponse } from "next/server";
// GET: Get all task templates
export async function GET() {
const templates = getAllTaskTemplates();
return NextResponse.json(templates);
}