diff --git a/src/app/admin/clients/[id]/actions.ts b/src/app/admin/clients/[id]/actions.ts
index e3b1098..a5b8229 100644
--- a/src/app/admin/clients/[id]/actions.ts
+++ b/src/app/admin/clients/[id]/actions.ts
@@ -142,6 +142,14 @@ export async function updatePhaseStatus(phaseId: string, id: string, status: str
revalidatePath(path);
}
+export async function deletePhase(phaseId: string, id: string) {
+ await requireAdmin();
+ // FK cascade on tasks and deliverables handles child rows
+ await db.delete(phases).where(eq(phases.id, phaseId));
+ const { path } = await resolveEntity(id);
+ revalidatePath(path);
+}
+
// ── TASKS ─────────────────────────────────────────────────────────────────────
export async function addTask(phaseId: string, id: string, formData: FormData) {
@@ -205,6 +213,17 @@ export async function updateTaskStatus(taskId: string, id: string, status: strin
revalidatePath(path);
}
+export async function deleteTask(taskId: string, id: string) {
+ await requireAdmin();
+ // Fetch phase_id before deletion so we can recompute phase status after
+ const taskRow = await db.select({ phase_id: tasks.phase_id }).from(tasks).where(eq(tasks.id, taskId)).limit(1);
+ const phaseId = taskRow[0]?.phase_id;
+ await db.delete(tasks).where(eq(tasks.id, taskId));
+ if (phaseId) await recomputePhaseStatus(phaseId);
+ const { path } = await resolveEntity(id);
+ revalidatePath(path);
+}
+
// ── DELIVERABLES ──────────────────────────────────────────────────────────────
export async function addDeliverable(taskId: string, id: string, formData: FormData) {
@@ -337,7 +356,7 @@ export async function postAdminComment(id: string, formData: FormData) {
if (!body || !entity) throw new Error("Dati mancanti");
const [entity_type, entity_id] = entity.split(":");
if (!entity_type || !entity_id) throw new Error("Formato entity non valido");
- const allowedTypes = ["task", "deliverable"];
+ const allowedTypes = ["task", "deliverable", "phase", "general"];
if (!allowedTypes.includes(entity_type)) throw new Error("entity_type non valido");
await db.insert(comments).values({ entity_type, entity_id, author: "admin", body });
const { path } = await resolveEntity(id);
diff --git a/src/app/api/client/comment/route.ts b/src/app/api/client/comment/route.ts
index 8fe07c5..1da9984 100644
--- a/src/app/api/client/comment/route.ts
+++ b/src/app/api/client/comment/route.ts
@@ -7,7 +7,7 @@ import { rateLimit } from "@/lib/rate-limit";
const commentSchema = z.object({
token: z.string().min(1),
- entity_type: z.enum(["task", "deliverable", "general"]),
+ entity_type: z.enum(["task", "deliverable", "general", "phase"]),
entity_id: z.string().min(1),
body: z.string().min(1, "Il commento non può essere vuoto").max(2000),
});
@@ -76,7 +76,12 @@ export async function POST(request: NextRequest) {
.from(tasks)
.where(inArray(tasks.phase_id, phaseIds));
- if (entity_type === "task") {
+ if (entity_type === "phase") {
+ // Phase: entity_id must be one of the client's phases
+ if (!phasesForClient.find((p) => p.id === entity_id)) {
+ return NextResponse.json({ error: "Accesso non consentito" }, { status: 403 });
+ }
+ } else if (entity_type === "task") {
if (!taskRows.find((r) => r.id === entity_id)) {
return NextResponse.json({ error: "Accesso non consentito" }, { status: 403 });
}
diff --git a/src/components/admin/AdminSidebar.tsx b/src/components/admin/AdminSidebar.tsx
index 49a990d..bac0c67 100644
--- a/src/components/admin/AdminSidebar.tsx
+++ b/src/components/admin/AdminSidebar.tsx
@@ -39,17 +39,6 @@ export function AdminSidebar() {
iamcavalli
- {/* CTA globale — genera preventivo */}
-
-
-
- Genera preventivo
-
-
-
{/* Nav links */}