148 lines
5.3 KiB
TypeScript
148 lines
5.3 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import { cookies } from "next/headers";
|
|
import { createRouteHandlerClient } from "@supabase/auth-helpers-nextjs";
|
|
import { sendInternalTicketCreatedEmail } from "@/lib/emailMigrationHelpers";
|
|
import { createSbServer, createSbServiceRole } from "@/lib/supabaseServer";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export async function GET(req: Request) {
|
|
const sb = createRouteHandlerClient({ cookies });
|
|
const url = new URL(req.url);
|
|
const status = url.searchParams.get("status");
|
|
const orgId = url.searchParams.get("org_id");
|
|
const limit = Math.min(parseInt(url.searchParams.get("limit") || "50", 10) || 50, 100);
|
|
const offset = parseInt(url.searchParams.get("offset") || "0", 10) || 0;
|
|
|
|
// Optional filters
|
|
let query = sb.from("tickets")
|
|
.select("id, org_id, subject, status, priority, created_by, assigned_to, source, last_message_at, message_count, unread_by_client, unread_by_staff, created_at, updated_at")
|
|
.order("last_message_at", { ascending: false })
|
|
.range(offset, offset + limit - 1);
|
|
|
|
if (status) query = query.eq("status", status);
|
|
if (orgId) query = query.eq("org_id", orgId);
|
|
|
|
const { data, error } = await query;
|
|
if (error) return NextResponse.json({ error: error.message }, { status: 400 });
|
|
return NextResponse.json({ items: data || [] });
|
|
}
|
|
|
|
export async function POST(req: Request) {
|
|
const sb = createRouteHandlerClient({ cookies });
|
|
const { data: { user } } = await sb.auth.getUser();
|
|
if (!user) return new NextResponse("Unauthorized", { status: 401 });
|
|
|
|
const body = await req.json().catch(() => ({}));
|
|
let { org_id, subject, message, priority } = body || {} as any;
|
|
subject = String(subject || "").trim();
|
|
message = String(message || "").trim();
|
|
priority = (priority || "normal").toString();
|
|
|
|
if (!subject || !message) {
|
|
return NextResponse.json({ error: "Sujet et message requis" }, { status: 400 });
|
|
}
|
|
|
|
// Determine if staff
|
|
let isStaff = false;
|
|
try {
|
|
const { data: s } = await sb.from("staff_users").select("is_staff").eq("user_id", user.id).maybeSingle();
|
|
isStaff = !!s?.is_staff;
|
|
} catch {}
|
|
|
|
// Determine org_id if missing
|
|
if (!org_id) {
|
|
if (isStaff) {
|
|
const c = cookies();
|
|
org_id = c.get("active_org_id")?.value || null;
|
|
} else {
|
|
const { data: m } = await sb
|
|
.from("organization_members")
|
|
.select("org_id")
|
|
.eq("user_id", user.id)
|
|
.eq("revoked", false)
|
|
.maybeSingle();
|
|
org_id = m?.org_id || null;
|
|
}
|
|
}
|
|
|
|
if (!org_id) return NextResponse.json({ error: "Impossible de déterminer l'organisation" }, { status: 400 });
|
|
|
|
const { data: ticket, error: tErr } = await sb
|
|
.from("tickets")
|
|
.insert({
|
|
org_id,
|
|
subject,
|
|
priority,
|
|
created_by: user.id,
|
|
source: isStaff ? "staff" : "web",
|
|
message_count: 1, // Initialiser à 1 puisqu'il y aura forcément le message initial
|
|
last_message_at: new Date().toISOString(),
|
|
unread_by_client: isStaff ? 1 : 0,
|
|
unread_by_staff: isStaff ? 0 : 1
|
|
})
|
|
.select("*")
|
|
.single();
|
|
if (tErr) return NextResponse.json({ error: tErr.message }, { status: 400 });
|
|
|
|
const { error: mErr } = await sb
|
|
.from("ticket_messages")
|
|
.insert({ ticket_id: ticket.id, author_id: user.id, body: message, internal: false, via: isStaff ? "staff" : "web" });
|
|
if (mErr) return NextResponse.json({ error: mErr.message }, { status: 400 });
|
|
|
|
// Corriger le message_count si le trigger l'a incrémenté (il devrait rester à 1)
|
|
await sb
|
|
.from("tickets")
|
|
.update({ message_count: 1 })
|
|
.eq("id", ticket.id);
|
|
|
|
// Envoyer une notification interne par email à paie@odentas.fr si le ticket n'est pas créé par le staff
|
|
if (!isStaff) {
|
|
try {
|
|
console.log('[TICKET CREATE] Sending internal notification email...');
|
|
|
|
// Récupérer les infos de l'utilisateur
|
|
const sbAdmin = createSbServiceRole();
|
|
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';
|
|
|
|
// Récupérer les infos de l'organisation
|
|
const { data: organization } = await sb
|
|
.from('organizations')
|
|
.select('name')
|
|
.eq('id', org_id)
|
|
.single();
|
|
|
|
// Récupérer le code employeur
|
|
const { data: orgDetails } = await sb
|
|
.from('organization_details')
|
|
.select('code_employeur')
|
|
.eq('org_id', org_id)
|
|
.single();
|
|
|
|
// Déterminer la catégorie du ticket (basée sur le sujet pour l'instant)
|
|
const category = 'Support général';
|
|
|
|
await sendInternalTicketCreatedEmail({
|
|
ticketId: ticket.id,
|
|
ticketSubject: subject,
|
|
ticketCategory: category,
|
|
ticketMessage: message,
|
|
userName,
|
|
userEmail: user.email || 'Email non disponible',
|
|
organizationName: organization?.name,
|
|
employerCode: orgDetails?.code_employeur,
|
|
});
|
|
|
|
console.log('[TICKET CREATE] Internal notification email sent successfully');
|
|
} catch (emailError) {
|
|
// Ne pas bloquer la création du ticket si l'email échoue
|
|
console.error('[TICKET CREATE] Failed to send internal notification email:', emailError);
|
|
}
|
|
}
|
|
|
|
return NextResponse.json(ticket, { status: 201 });
|
|
}
|
|
|