feat: add contact management functionality

- Implemented ContactForm component for creating and editing contacts.
- Added ProjectContactSelector component to manage project-specific contacts.
- Updated ProjectForm to include ProjectContactSelector for associating contacts with projects.
- Enhanced Card component with a new CardTitle subcomponent for better structure.
- Updated Navigation to include a link to the contacts page.
- Added translations for contact-related terms in the i18n module.
- Initialized contacts database schema and created necessary tables for contact management.
- Developed queries for CRUD operations on contacts, including linking and unlinking contacts to projects.
- Created a test script to validate contact queries against the database.
This commit is contained in:
2025-12-03 16:23:05 +01:00
parent c9b7355f3c
commit 60b79fa360
18 changed files with 2332 additions and 10 deletions

View File

@@ -0,0 +1,103 @@
import { NextResponse } from "next/server";
import {
getContactById,
updateContact,
deleteContact,
hardDeleteContact,
} from "@/lib/queries/contacts";
import { withAuth } from "@/lib/middleware/auth";
// GET: Get contact by ID
async function getContactHandler(req, { params }) {
try {
const contactId = parseInt(params.id);
const contact = getContactById(contactId);
if (!contact) {
return NextResponse.json(
{ error: "Contact not found" },
{ status: 404 }
);
}
return NextResponse.json(contact);
} catch (error) {
console.error("Error fetching contact:", error);
return NextResponse.json(
{ error: "Failed to fetch contact" },
{ status: 500 }
);
}
}
// PUT: Update contact
async function updateContactHandler(req, { params }) {
try {
const contactId = parseInt(params.id);
const data = await req.json();
// Validate contact type if provided
if (data.contact_type) {
const validTypes = [
"project",
"contractor",
"office",
"supplier",
"other",
];
if (!validTypes.includes(data.contact_type)) {
return NextResponse.json(
{ error: "Invalid contact type" },
{ status: 400 }
);
}
}
const contact = updateContact(contactId, data);
if (!contact) {
return NextResponse.json(
{ error: "Contact not found" },
{ status: 404 }
);
}
return NextResponse.json(contact);
} catch (error) {
console.error("Error updating contact:", error);
return NextResponse.json(
{ error: "Failed to update contact" },
{ status: 500 }
);
}
}
// DELETE: Delete contact (soft delete or hard delete)
async function deleteContactHandler(req, { params }) {
try {
const contactId = parseInt(params.id);
const { searchParams } = new URL(req.url);
const hard = searchParams.get("hard") === "true";
if (hard) {
// Hard delete - permanently remove
hardDeleteContact(contactId);
} else {
// Soft delete - set is_active to 0
deleteContact(contactId);
}
return NextResponse.json({ message: "Contact deleted successfully" });
} catch (error) {
console.error("Error deleting contact:", error);
return NextResponse.json(
{ error: "Failed to delete contact" },
{ status: 500 }
);
}
}
// Protected routes - require authentication
export const GET = withAuth(getContactHandler);
export const PUT = withAuth(updateContactHandler);
export const DELETE = withAuth(deleteContactHandler);