138 lines
5.4 KiB
TypeScript
138 lines
5.4 KiB
TypeScript
"use client";
|
|
import { useState, useEffect } from "react";
|
|
import { TicketReplyConfirmationModal } from "./TicketReplyConfirmationModal";
|
|
|
|
export default function StaffTicketActions({ ticketId, status, mode = "both" }: { ticketId: string; status: string; mode?: "status" | "message" | "both" }) {
|
|
const [updating, setUpdating] = useState(false);
|
|
const [sending, setSending] = useState(false);
|
|
const [showModal, setShowModal] = useState(false);
|
|
const [pendingMessage, setPendingMessage] = useState({ body: "", internal: false });
|
|
const [recipientInfo, setRecipientInfo] = useState<{ email: string; name: string } | null>(null);
|
|
|
|
// Récupérer les informations du destinataire
|
|
useEffect(() => {
|
|
async function fetchRecipientInfo() {
|
|
try {
|
|
console.log('🔍 [StaffTicketActions] Fetching recipient info for ticket:', ticketId);
|
|
const url = `/api/tickets/${ticketId}/recipient-info`;
|
|
console.log('🔍 [StaffTicketActions] URL:', url);
|
|
|
|
const res = await fetch(url, { credentials: 'include' });
|
|
console.log('🔍 [StaffTicketActions] Response status:', res.status);
|
|
|
|
if (res.ok) {
|
|
const data = await res.json();
|
|
console.log('✅ [StaffTicketActions] Recipient info:', data);
|
|
setRecipientInfo(data);
|
|
} else {
|
|
const errorText = await res.text();
|
|
console.error('❌ [StaffTicketActions] Error response:', res.status, errorText);
|
|
}
|
|
} catch (e) {
|
|
console.error('❌ [StaffTicketActions] Erreur lors de la récupération des infos destinataire:', e);
|
|
}
|
|
}
|
|
fetchRecipientInfo();
|
|
}, [ticketId]);
|
|
|
|
async function onStatusSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
e.preventDefault();
|
|
const fd = new FormData(e.currentTarget);
|
|
const next = String(fd.get('status') || 'open');
|
|
setUpdating(true);
|
|
try {
|
|
const res = await fetch(`/api/tickets/${ticketId}`, { method: 'PATCH', credentials: 'include', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ status: next }) });
|
|
if (!res.ok) throw new Error(await res.text());
|
|
location.reload();
|
|
} catch (e: any) {
|
|
alert('Erreur: ' + (e?.message || 'inconnue'));
|
|
} finally {
|
|
setUpdating(false);
|
|
}
|
|
}
|
|
|
|
async function onMessageSubmit(e: React.FormEvent<HTMLFormElement>) {
|
|
e.preventDefault();
|
|
const form = e.currentTarget;
|
|
const fd = new FormData(form);
|
|
const body = String(fd.get('body') || '').trim();
|
|
const internal = fd.get('internal') === 'on';
|
|
|
|
if (!body) return;
|
|
|
|
// Si c'est une note interne, envoyer directement
|
|
if (internal) {
|
|
await sendMessage(body, internal, form);
|
|
} else {
|
|
// Sinon, afficher le modal de confirmation
|
|
setPendingMessage({ body, internal });
|
|
setShowModal(true);
|
|
}
|
|
}
|
|
|
|
async function sendMessage(body: string, internal: boolean, formToReset?: HTMLFormElement) {
|
|
setSending(true);
|
|
try {
|
|
const res = await fetch(`/api/tickets/${ticketId}/messages`, {
|
|
method: 'POST',
|
|
credentials: 'include',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ body, internal })
|
|
});
|
|
if (!res.ok) throw new Error(await res.text());
|
|
|
|
if (formToReset) formToReset.reset();
|
|
location.reload();
|
|
} catch (e: any) {
|
|
alert('Erreur: ' + (e?.message || 'inconnue'));
|
|
} finally {
|
|
setSending(false);
|
|
setShowModal(false);
|
|
}
|
|
}
|
|
|
|
function handleConfirmSend() {
|
|
// Récupérer le formulaire pour le reset
|
|
const form = document.querySelector('form[data-ticket-form]') as HTMLFormElement;
|
|
sendMessage(pendingMessage.body, pendingMessage.internal, form);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{(mode === 'status' || mode === 'both') && (
|
|
<form className="flex items-center gap-2" onSubmit={onStatusSubmit}>
|
|
<select name="status" defaultValue={status} className="px-2 py-1 rounded-md border text-sm bg-transparent">
|
|
<option value="open">Ouvert</option>
|
|
<option value="waiting_client">En attente client</option>
|
|
<option value="waiting_staff">En attente support</option>
|
|
<option value="closed">Fermé</option>
|
|
</select>
|
|
<button disabled={updating} className="inline-flex items-center px-3 py-2 rounded-lg bg-slate-200 text-sm disabled:opacity-50">Mettre à jour</button>
|
|
</form>
|
|
)}
|
|
|
|
{(mode === 'message' || mode === 'both') && (
|
|
<form className="space-y-2" onSubmit={onMessageSubmit} data-ticket-form>
|
|
<textarea name="body" className="w-full px-3 py-2 rounded-lg border bg-transparent text-sm min-h-[120px]" placeholder="Réponse…" />
|
|
<div className="flex items-center gap-3">
|
|
<label className="inline-flex items-center gap-2 text-sm"><input type="checkbox" name="internal" /> Note interne</label>
|
|
<button disabled={sending} className="ml-auto inline-flex items-center px-3 py-2 rounded-lg bg-emerald-600 text-white text-sm hover:bg-emerald-700 disabled:opacity-50">Envoyer</button>
|
|
</div>
|
|
</form>
|
|
)}
|
|
|
|
{/* Modal de confirmation */}
|
|
{recipientInfo && (
|
|
<TicketReplyConfirmationModal
|
|
isOpen={showModal}
|
|
recipientEmail={recipientInfo.email}
|
|
recipientName={recipientInfo.name}
|
|
messageBody={pendingMessage.body}
|
|
onConfirm={handleConfirmSend}
|
|
onCancel={() => setShowModal(false)}
|
|
isLoading={sending}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|