espace-paie-odentas/app/api/tickets/[id]/messages/route.ts

227 lines
8.4 KiB
TypeScript

import { NextResponse } from "next/server";
import { createSbServer, createSbServiceRole } from "@/lib/supabaseServer";
import { sendSupportReplyEmail, sendInternalTicketReplyEmail } from "@/lib/emailMigrationHelpers";
export const dynamic = "force-dynamic";
export async function GET(_: Request, { params }: { params: { id: string } }) {
const sb = createSbServer();
// Récupérer les messages
const { data: messages, error } = await sb
.from("ticket_messages")
.select("id, ticket_id, author_id, body, internal, via, created_at")
.eq("ticket_id", params.id)
.order("created_at", { ascending: true });
if (error) return NextResponse.json({ error: error.message }, { status: 400 });
if (!messages || messages.length === 0) {
return NextResponse.json({ items: [] });
}
// Récupérer les informations staff pour tous les auteurs
const authorIds = [...new Set(messages.map(m => m.author_id))];
const { data: staffUsers } = await sb
.from("staff_users")
.select("user_id, is_staff")
.in("user_id", authorIds);
// Créer un map pour faciliter la recherche
const staffMap = new Map((staffUsers || []).map(s => [s.user_id, s.is_staff]));
// Enrichir les messages avec les informations staff
const enrichedMessages = messages.map(msg => ({
...msg,
is_staff: staffMap.get(msg.author_id) === true
}));
return NextResponse.json({ items: enrichedMessages });
}
export async function POST(req: Request, { params }: { params: { id: string } }) {
const sb = createSbServer();
const { data: { user } } = await sb.auth.getUser();
if (!user) return new NextResponse("Unauthorized", { status: 401 });
const body = await req.json().catch(() => ({}));
const text = String(body.body || "").trim();
const internal = body.internal === true;
if (!text) return NextResponse.json({ error: "Message vide" }, { status: 400 });
// Vérifier si l'utilisateur est staff
const { data: staffUser } = await sb
.from("staff_users")
.select("is_staff")
.eq("user_id", user.id)
.maybeSingle();
const isStaff = staffUser?.is_staff === true;
const via = isStaff ? "staff" : "web";
const { error } = await sb
.from("ticket_messages")
.insert({
ticket_id: params.id,
author_id: user.id,
body: text,
internal,
via
});
if (error) return NextResponse.json({ error: error.message }, { status: 400 });
// Si c'est un message du staff et qu'il n'est pas interne, envoyer une notification par email
if (isStaff && !internal) {
try {
console.log('📧 [POST messages] Envoi de notification email...');
// Récupérer les informations du ticket
const { data: ticket } = await sb
.from("tickets")
.select("id, subject, created_by, org_id")
.eq("id", params.id)
.single();
console.log('📧 [POST messages] Ticket:', { id: ticket?.id, created_by: ticket?.created_by, org_id: ticket?.org_id });
if (ticket && ticket.created_by) {
// Récupérer les informations de l'organisation
const { data: organization } = await sb
.from("organizations")
.select("name, structure_api")
.eq("id", ticket.org_id)
.single();
console.log('📧 [POST messages] Organization:', { name: organization?.name, structure_api: organization?.structure_api });
// Récupérer le code employeur depuis organization_details
const { data: orgDetails } = await sb
.from("organization_details")
.select("code_employeur")
.eq("org_id", ticket.org_id)
.maybeSingle();
console.log('📧 [POST messages] Org details:', { code_employeur: orgDetails?.code_employeur });
// Utiliser le service role pour accéder aux données auth
const sbAdmin = createSbServiceRole();
// Récupérer l'email et le prénom du créateur du ticket
const { data: creatorUser, error: creatorError } = await sbAdmin.auth.admin.getUserById(ticket.created_by);
console.log('📧 [POST messages] Creator user:', {
hasData: !!creatorUser,
email: creatorUser?.user?.email,
error: creatorError
});
// Récupérer le nom du staff qui répond
const { data: staffProfile, error: staffError } = await sbAdmin.auth.admin.getUserById(user.id);
console.log('📧 [POST messages] Staff profile:', {
hasData: !!staffProfile,
email: staffProfile?.user?.email,
error: staffError
});
if (creatorUser?.user?.email) {
// Récupérer le prénom depuis user_metadata
const firstName = creatorUser.user.user_metadata?.display_name ||
creatorUser.user.user_metadata?.first_name ||
undefined;
// Récupérer le nom du staff depuis user_metadata
const staffName = staffProfile?.user?.user_metadata?.display_name ||
staffProfile?.user?.user_metadata?.first_name ||
staffProfile?.user?.email?.split('@')[0] ||
'L\'équipe support';
console.log('📧 [POST messages] Envoi vers:', creatorUser.user.email);
console.log('📧 [POST messages] Données email:', {
firstName,
staffName,
ticketId: ticket.id,
ticketSubject: ticket.subject,
organizationName: organization?.name,
employerCode: orgDetails?.code_employeur
});
// Utiliser le helper pour envoyer l'email
await sendSupportReplyEmail(creatorUser.user.email, {
firstName,
ticketId: ticket.id,
ticketSubject: ticket.subject,
staffName,
staffMessage: text,
organizationName: organization?.name,
employerCode: orgDetails?.code_employeur,
});
console.log(`✅ [POST messages] Notification email envoyée à ${creatorUser.user.email} pour le ticket ${ticket.id}`);
} else {
console.error('❌ [POST messages] Email du créateur introuvable');
}
} else {
console.error('❌ [POST messages] Ticket ou created_by introuvable');
}
} catch (emailError) {
// On ne fait pas échouer la requête si l'email échoue
console.error('❌ [POST messages] Erreur lors de l\'envoi de la notification email:', emailError);
}
}
// Si c'est un message d'un utilisateur (non-staff), envoyer une notification interne
if (!isStaff) {
try {
console.log('📧 [POST messages] Envoi de notification interne...');
// Récupérer les informations du ticket
const { data: ticket } = await sb
.from("tickets")
.select("id, subject, status, org_id")
.eq("id", params.id)
.single();
if (ticket) {
// Récupérer les informations de l'organisation
const { data: organization } = await sb
.from("organizations")
.select("name")
.eq("id", ticket.org_id)
.single();
// Récupérer le code employeur depuis organization_details
const { data: orgDetails } = await sb
.from("organization_details")
.select("code_employeur")
.eq("org_id", ticket.org_id)
.maybeSingle();
// Utiliser le service role pour accéder aux données auth
const sbAdmin = createSbServiceRole();
// Récupérer les infos de l'utilisateur qui répond
const { data: userData } = await sbAdmin.auth.admin.getUserById(user.id);
const userName = userData?.user?.user_metadata?.display_name
|| userData?.user?.user_metadata?.first_name
|| 'Utilisateur inconnu';
await sendInternalTicketReplyEmail({
ticketId: ticket.id,
ticketSubject: ticket.subject,
ticketStatus: ticket.status,
userMessage: text,
userName,
userEmail: user.email || 'Email non disponible',
organizationName: organization?.name,
employerCode: orgDetails?.code_employeur,
});
console.log(`✅ [POST messages] Notification interne envoyée pour le ticket ${ticket.id}`);
}
} catch (emailError) {
console.error('❌ [POST messages] Erreur lors de l\'envoi de la notification interne:', emailError);
}
}
return NextResponse.json({ ok: true }, { status: 201 });
}