"use server"; import { revalidatePath } from "next/cache"; import { getServerSession } from "next-auth"; import { eq } from "drizzle-orm"; import { authOptions } from "@/lib/auth"; import { db } from "@/db"; import { clients, comments } from "@/db/schema"; async function requireAdmin() { const session = await getServerSession(authOptions); if (!session) throw new Error("Non autorizzato"); } /** * Admin reply from the Conversazioni inbox. Per project decision, replies are * saved as a "general" comment on the client (entity_id = clientId), so they * surface in the client's general chat and in the client detail CommentsTab. */ export async function replyToConversation(clientId: string, formData: FormData) { await requireAdmin(); const body = (formData.get("body") as string)?.trim(); if (!clientId || !body) throw new Error("Dati mancanti"); // Validate the client exists (entity_id integrity). const rows = await db .select({ id: clients.id }) .from(clients) .where(eq(clients.id, clientId)) .limit(1); if (rows.length === 0) throw new Error("Cliente non trovato"); await db.insert(comments).values({ entity_type: "general", entity_id: clientId, author: "admin", body, }); // Replying implies the admin has read the incoming messages. await db .update(clients) .set({ admin_last_read_at: new Date() }) .where(eq(clients.id, clientId)); revalidatePath("/admin/conversazioni"); revalidatePath(`/admin/clients/${clientId}`); } /** Mark a client's conversation as read up to now (clears unread dot/badge). */ export async function markConversationRead(clientId: string) { await requireAdmin(); if (!clientId) return; await db .update(clients) .set({ admin_last_read_at: new Date() }) .where(eq(clients.id, clientId)); revalidatePath("/admin/conversazioni"); }