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:
39
src/app/api/contracts/route.js
Normal file
39
src/app/api/contracts/route.js
Normal 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 });
|
||||
}
|
||||
44
src/app/api/notes/route.js
Normal file
44
src/app/api/notes/route.js
Normal 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 });
|
||||
}
|
||||
40
src/app/api/project-tasks/[id]/route.js
Normal file
40
src/app/api/project-tasks/[id]/route.js
Normal 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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
52
src/app/api/project-tasks/route.js
Normal file
52
src/app/api/project-tasks/route.js
Normal 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 }
|
||||
);
|
||||
}
|
||||
}
|
||||
22
src/app/api/projects/[id]/route.js
Normal file
22
src/app/api/projects/[id]/route.js
Normal 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 });
|
||||
}
|
||||
17
src/app/api/projects/route.js
Normal file
17
src/app/api/projects/route.js
Normal 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 });
|
||||
}
|
||||
20
src/app/api/tasks/route.js
Normal file
20
src/app/api/tasks/route.js
Normal 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 });
|
||||
}
|
||||
8
src/app/api/tasks/templates/route.js
Normal file
8
src/app/api/tasks/templates/route.js
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user