545065b527
Build & Auto-Repair / build (push) Has been cancelled
- Kanban board with drag-and-drop per stage, colour-coded cards, score bars - Project Management with milestones, Gantt timeline, inline add milestone/task - Proposal/Quote builder with line items, VAT, terms, e-signature capture - Time Tracking with stopwatch, manual entry, hours-by-project chart - Custom Fields system: admin-defined fields per entity (leads/customers/ projects/opportunities) with drag-and-drop reordering in settings - Reusable CustomFieldsSection component for entity detail pages - Customers API endpoint - All builds pass with zero errors
61 lines
2.3 KiB
TypeScript
61 lines
2.3 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server"
|
|
import { getSessionUser } from "@/lib/auth"
|
|
import { query } from "@/lib/db"
|
|
|
|
export async function PATCH(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
|
try {
|
|
const user = await getSessionUser()
|
|
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
|
|
|
|
const { id } = await params
|
|
const body = await request.json()
|
|
|
|
const fields: string[] = []
|
|
const values: any[] = []
|
|
let idx = 1
|
|
|
|
if (body.name !== undefined) { fields.push(`name = $${idx++}`); values.push(body.name) }
|
|
if (body.description !== undefined) { fields.push(`description = $${idx++}`); values.push(body.description) }
|
|
if (body.status !== undefined) { fields.push(`status = $${idx++}`); values.push(body.status) }
|
|
if (body.startDate !== undefined) { fields.push(`start_date = $${idx++}`); values.push(body.startDate) }
|
|
if (body.dueDate !== undefined) { fields.push(`due_date = $${idx++}`); values.push(body.dueDate) }
|
|
|
|
if (body.status === "completed") {
|
|
fields.push(`completed_at = NOW()`)
|
|
}
|
|
|
|
if (fields.length === 0) {
|
|
return NextResponse.json({ error: "No fields to update" }, { status: 400 })
|
|
}
|
|
|
|
fields.push(`updated_at = NOW()`)
|
|
values.push(id)
|
|
|
|
const sql = `UPDATE project_milestones SET ${fields.join(", ")} WHERE id = $${idx} RETURNING id`
|
|
const result = await query(sql, values)
|
|
|
|
if (result.rows.length === 0) {
|
|
return NextResponse.json({ error: "Milestone not found" }, { status: 404 })
|
|
}
|
|
|
|
return NextResponse.json({ success: true, id: result.rows[0].id })
|
|
} catch (error) {
|
|
console.error("Milestone PATCH error:", error)
|
|
return NextResponse.json({ error: "Failed to update milestone" }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function DELETE(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
|
try {
|
|
const user = await getSessionUser()
|
|
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
|
|
|
|
const { id } = await params
|
|
await query("DELETE FROM project_milestones WHERE id = $1", [id])
|
|
return NextResponse.json({ success: true })
|
|
} catch (error) {
|
|
console.error("Milestone DELETE error:", error)
|
|
return NextResponse.json({ error: "Failed to delete milestone" }, { status: 500 })
|
|
}
|
|
}
|