espace-paie-odentas/components/staff/avenants/AvenantDetailPageClient.tsx

734 lines
30 KiB
TypeScript

"use client";
import { useRouter } from "next/navigation";
import { ArrowLeft, Calendar, FileText, User, Building2, Download, Trash2, RefreshCw, Send, Check, X, Clock, Edit3 } from "lucide-react";
import { useEffect, useState } from "react";
import DeleteAvenantModal from "@/components/staff/amendments/DeleteAvenantModal";
import SendSignatureModal from "@/components/staff/amendments/SendSignatureModal";
import ChangeStatusModal from "@/components/staff/amendments/ChangeStatusModal";
import UpdateSignatureStatusModal from "@/components/staff/amendments/UpdateSignatureStatusModal";
interface AvenantDetailPageClientProps {
avenant: any;
}
export default function AvenantDetailPageClient({ avenant }: AvenantDetailPageClientProps) {
const router = useRouter();
const [pdfUrl, setPdfUrl] = useState<string | null>(null);
const [loadingPdf, setLoadingPdf] = useState(false);
const [showDeleteModal, setShowDeleteModal] = useState(false);
const [isDeleting, setIsDeleting] = useState(false);
const [isRegeneratingPdf, setIsRegeneratingPdf] = useState(false);
const [isSendingSignature, setIsSendingSignature] = useState(false);
const [showSendSignatureModal, setShowSendSignatureModal] = useState(false);
const [sendSignatureSuccess, setSendSignatureSuccess] = useState(false);
const [showChangeStatusModal, setShowChangeStatusModal] = useState(false);
const [isChangingStatus, setIsChangingStatus] = useState(false);
const [showUpdateSignatureModal, setShowUpdateSignatureModal] = useState(false);
const [isUpdatingSignature, setIsUpdatingSignature] = useState(false);
// Charger l'URL du PDF si la clé S3 existe
useEffect(() => {
if (avenant.pdf_s3_key) {
setLoadingPdf(true);
fetch(`/api/staff/amendments/${avenant.id}/pdf-url`)
.then(res => res.json())
.then(data => {
if (data.presignedUrl) {
setPdfUrl(data.presignedUrl);
}
})
.catch(err => console.error("Erreur chargement URL PDF:", err))
.finally(() => setLoadingPdf(false));
}
}, [avenant.id, avenant.pdf_s3_key]);
const handleDelete = async () => {
setIsDeleting(true);
try {
const response = await fetch(`/api/staff/amendments/${avenant.id}`, {
method: "DELETE",
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Erreur lors de la suppression");
}
// Rediriger vers la liste des avenants
router.push("/staff/avenants");
} catch (error: any) {
console.error("Erreur suppression avenant:", error);
alert("Erreur lors de la suppression de l'avenant: " + error.message);
setIsDeleting(false);
setShowDeleteModal(false);
}
};
const handleRegeneratePdf = async () => {
setIsRegeneratingPdf(true);
try {
// Préparer les données de l'avenant pour la génération
const amendmentData = {
contract_id: avenant.contract_id,
date_effet: avenant.date_effet,
date_signature: avenant.date_avenant,
elements: avenant.elements_avenantes,
objet_data: avenant.objet_data,
duree_data: avenant.duree_data,
lieu_horaire_data: avenant.lieu_horaire_data,
remuneration_data: avenant.remuneration_data,
};
// Générer le PDF
const generateResponse = await fetch("/api/staff/amendments/generate-pdf", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
contractId: avenant.contract_id,
amendmentData,
}),
});
if (!generateResponse.ok) {
const error = await generateResponse.json();
throw new Error(error.error || "Erreur lors de la génération du PDF");
}
const { s3Key, presignedUrl } = await generateResponse.json();
// Mettre à jour l'avenant avec la nouvelle clé S3
const updateResponse = await fetch(`/api/staff/amendments/${avenant.id}/update-pdf`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
pdf_s3_key: s3Key,
}),
});
if (!updateResponse.ok) {
const error = await updateResponse.json();
throw new Error(error.error || "Erreur lors de la mise à jour");
}
// Mettre à jour l'URL affichée
setPdfUrl(presignedUrl);
alert("PDF régénéré avec succès !");
// Recharger la page pour avoir les nouvelles données
router.refresh();
} catch (error: any) {
console.error("Erreur regénération PDF:", error);
alert("Erreur lors de la regénération du PDF: " + error.message);
} finally {
setIsRegeneratingPdf(false);
}
};
const handleSendForSignature = async () => {
if (!avenant.pdf_s3_key) {
alert("Vous devez d'abord générer le PDF avant de l'envoyer en signature.");
return;
}
setIsSendingSignature(true);
setSendSignatureSuccess(false);
try {
const response = await fetch(`/api/staff/amendments/${avenant.id}/send-signature`, {
method: "POST",
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Erreur lors de l'envoi");
}
const data = await response.json();
// Afficher le succès dans le modal
setSendSignatureSuccess(true);
// Recharger la page après 2 secondes pour voir le nouveau statut
setTimeout(() => {
router.refresh();
}, 2000);
} catch (error: any) {
console.error("Erreur envoi signature:", error);
alert("Erreur lors de l'envoi en signature: " + error.message);
setShowSendSignatureModal(false);
} finally {
setIsSendingSignature(false);
}
};
const handleChangeStatus = async (newStatus: string) => {
setIsChangingStatus(true);
try {
const response = await fetch(`/api/staff/amendments/${avenant.id}/change-status`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ status: newStatus }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Erreur lors du changement de statut");
}
// Fermer le modal et recharger la page
setShowChangeStatusModal(false);
router.refresh();
} catch (error: any) {
console.error("Erreur changement statut:", error);
alert("Erreur lors du changement de statut: " + error.message);
} finally {
setIsChangingStatus(false);
}
};
const handleUpdateSignatureStatus = async (newSignatureStatus: string) => {
setIsUpdatingSignature(true);
try {
const response = await fetch(`/api/staff/amendments/${avenant.id}/update-signature-status`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ signature_status: newSignatureStatus }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.error || "Erreur lors de la mise à jour du statut de signature");
}
// Fermer le modal et recharger la page
setShowUpdateSignatureModal(false);
alert("Statut de signature mis à jour avec succès !");
router.refresh();
} catch (error: any) {
console.error("Erreur mise à jour statut signature:", error);
alert("Erreur lors de la mise à jour du statut de signature: " + error.message);
} finally {
setIsUpdatingSignature(false);
}
};
const contract = avenant.cddu_contracts;
const formatDate = (dateStr?: string) => {
if (!dateStr) return "-";
const [y, m, d] = dateStr.split("-");
return `${d}/${m}/${y}`;
};
const getStatusBadge = (status: string) => {
const badges = {
draft: "bg-slate-100 text-slate-700",
pending: "bg-orange-100 text-orange-700",
signed: "bg-green-100 text-green-700",
cancelled: "bg-red-100 text-red-700",
};
const labels = {
draft: "Brouillon",
pending: "En attente",
signed: "Signé",
cancelled: "Annulé",
};
return (
<span className={`px-3 py-1 text-sm font-medium rounded-full ${badges[status as keyof typeof badges] || badges.draft}`}>
{labels[status as keyof typeof labels] || status}
</span>
);
};
const getTypeBadge = (type: string) => {
const badges = {
modification: "bg-blue-100 text-blue-700",
annulation: "bg-red-100 text-red-700",
};
const labels = {
modification: "Modification",
annulation: "Annulation",
};
return (
<span className={`px-3 py-1 text-sm font-medium rounded-full ${badges[type as keyof typeof badges] || badges.modification}`}>
{labels[type as keyof typeof labels] || type}
</span>
);
};
const getElementLabel = (element: string) => {
const labels: Record<string, string> = {
objet: "Objet (profession, production)",
duree: "Durée de l'engagement",
lieu_horaire: "Lieu et horaires",
remuneration: "Rémunération",
};
return labels[element] || element;
};
const getSignatureStatusBadge = (status?: string) => {
if (!status || status === 'not_sent') {
return (
<span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-slate-100 text-slate-700 rounded-full text-sm font-medium">
<Clock className="w-4 h-4" />
Non envoyé
</span>
);
}
if (status === 'pending_employer') {
return (
<span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-orange-100 text-orange-700 rounded-full text-sm font-medium">
<Clock className="w-4 h-4" />
En attente employeur
</span>
);
}
if (status === 'pending_employee') {
return (
<span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-blue-100 text-blue-700 rounded-full text-sm font-medium">
<Clock className="w-4 h-4" />
En attente salarié
</span>
);
}
if (status === 'signed') {
return (
<span className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-green-100 text-green-700 rounded-full text-sm font-medium">
<Check className="w-4 h-4" />
Signé
</span>
);
}
return null;
};
return (
<div className="max-w-5xl mx-auto space-y-6">
{/* Header avec bouton retour */}
<div className="flex items-center gap-4">
<button
onClick={() => router.push("/staff/avenants")}
className="p-2 hover:bg-slate-100 rounded-lg transition-colors"
>
<ArrowLeft className="h-5 w-5 text-slate-600" />
</button>
<div className="flex-1">
<h1 className="text-2xl font-bold text-slate-900">
Avenant {avenant.numero_avenant}
</h1>
<p className="text-sm text-slate-600 mt-1">
Contrat {contract?.contract_number}
</p>
</div>
<div className="flex items-center gap-3">
{getStatusBadge(avenant.statut)}
{getTypeBadge(avenant.type_avenant)}
<button
onClick={() => setShowChangeStatusModal(true)}
className="inline-flex items-center gap-2 px-4 py-2 border border-indigo-300 text-indigo-700 rounded-lg hover:bg-indigo-50 transition-colors"
title="Changer le statut manuellement"
>
<Edit3 className="h-4 w-4" />
Changer statut
</button>
<button
onClick={() => setShowDeleteModal(true)}
className="inline-flex items-center gap-2 px-4 py-2 border border-red-300 text-red-700 rounded-lg hover:bg-red-50 transition-colors"
>
<Trash2 className="h-4 w-4" />
Supprimer
</button>
</div>
</div>
{/* Informations générales */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<h2 className="font-semibold text-slate-900 mb-4 flex items-center gap-2">
<FileText className="h-5 w-5" />
Informations générales
</h2>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="text-sm font-medium text-slate-500">Date d'effet</label>
<div className="mt-1 text-slate-900">{formatDate(avenant.date_effet)}</div>
</div>
<div>
<label className="text-sm font-medium text-slate-500">Date de signature</label>
<div className="mt-1 text-slate-900">{formatDate(avenant.date_avenant)}</div>
</div>
{avenant.motif_avenant && (
<div className="col-span-2">
<label className="text-sm font-medium text-slate-500">Motif</label>
<div className="mt-1 text-slate-900">{avenant.motif_avenant}</div>
</div>
)}
</div>
</div>
{/* Informations du contrat */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<h2 className="font-semibold text-slate-900 mb-4 flex items-center gap-2">
<User className="h-5 w-5" />
Contrat concerné
</h2>
<div className="grid grid-cols-2 gap-6">
<div>
<label className="text-sm font-medium text-slate-500">Salarié</label>
<div className="mt-1 text-slate-900">
{contract?.employee_name}
{contract?.employee_matricule && (
<span className="text-slate-500 ml-2">({contract.employee_matricule})</span>
)}
</div>
</div>
<div>
<label className="text-sm font-medium text-slate-500">Organisation</label>
<div className="mt-1 text-slate-900">{contract?.structure}</div>
</div>
<div>
<label className="text-sm font-medium text-slate-500">Type de contrat</label>
<div className="mt-1 text-slate-900">{contract?.type_de_contrat}</div>
</div>
<div>
<label className="text-sm font-medium text-slate-500">Période</label>
<div className="mt-1 text-slate-900">
{formatDate(contract?.start_date)} - {formatDate(contract?.end_date)}
</div>
</div>
</div>
</div>
{/* Signatures électroniques */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="font-semibold text-slate-900 flex items-center gap-2">
<Send className="h-5 w-5" />
Signatures électroniques
</h2>
<button
onClick={() => setShowUpdateSignatureModal(true)}
className="inline-flex items-center gap-2 px-3 py-1.5 text-sm border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 transition-colors"
title="Mettre à jour manuellement le statut de signature"
>
<Edit3 className="h-3.5 w-3.5" />
Modifier statut signature
</button>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-lg">
<div>
<div className="text-sm font-medium text-slate-900">Statut global</div>
<div className="text-xs text-slate-600 mt-0.5">État actuel du processus de signature</div>
</div>
<div>
{getSignatureStatusBadge(avenant.signature_status)}
</div>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 border rounded-lg">
<div className="flex items-center justify-between mb-2">
<div className="text-sm font-medium text-slate-900">Employeur</div>
{avenant.signature_status === 'pending_employee' || avenant.signature_status === 'signed' ? (
<Check className="w-5 h-5 text-green-600" strokeWidth={3} />
) : avenant.signature_status === 'pending_employer' ? (
<X className="w-5 h-5 text-red-600" strokeWidth={3} />
) : (
<Clock className="w-5 h-5 text-slate-400" />
)}
</div>
{avenant.last_employer_notification_at && (
<div className="text-xs text-slate-600">
Notifié le {new Date(avenant.last_employer_notification_at).toLocaleDateString('fr-FR')}
</div>
)}
</div>
<div className="p-4 border rounded-lg">
<div className="flex items-center justify-between mb-2">
<div className="text-sm font-medium text-slate-900">Salarié</div>
{avenant.signature_status === 'signed' ? (
<Check className="w-5 h-5 text-green-600" strokeWidth={3} />
) : avenant.signature_status === 'pending_employee' || avenant.signature_status === 'pending_employer' ? (
<X className="w-5 h-5 text-red-600" strokeWidth={3} />
) : (
<Clock className="w-5 h-5 text-slate-400" />
)}
</div>
{avenant.last_employee_notification_at && (
<div className="text-xs text-slate-600">
Notifié le {new Date(avenant.last_employee_notification_at).toLocaleDateString('fr-FR')}
</div>
)}
</div>
</div>
</div>
</div>
{/* Éléments modifiés */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<h2 className="font-semibold text-slate-900 mb-4">Éléments modifiés</h2>
<div className="space-y-4">
{avenant.elements_avenantes?.map((element: string) => (
<div key={element} className="border-l-4 border-indigo-500 pl-4 py-2">
<h3 className="font-medium text-slate-900 mb-2">{getElementLabel(element)}</h3>
{element === "objet" && avenant.objet_data && (
<div className="text-sm text-slate-600 space-y-1">
{avenant.objet_data.profession_label && (
<div>Profession : {avenant.objet_data.profession_label}</div>
)}
{avenant.objet_data.production_name && (
<div>Production : {avenant.objet_data.production_name}</div>
)}
{avenant.objet_data.production_numero_objet && (
<div>N° objet : {avenant.objet_data.production_numero_objet}</div>
)}
</div>
)}
{element === "duree" && avenant.duree_data && (
<div className="text-sm text-slate-600 space-y-1">
{avenant.duree_data.date_debut && (
<div>Nouvelle date de début : {formatDate(avenant.duree_data.date_debut)}</div>
)}
{avenant.duree_data.date_fin && (
<div>Nouvelle date de fin : {formatDate(avenant.duree_data.date_fin)}</div>
)}
{/* Pour les artistes */}
{avenant.duree_data.nb_representations !== undefined && avenant.duree_data.nb_representations > 0 && (
<div>Représentations : {avenant.duree_data.nb_representations}</div>
)}
{avenant.duree_data.nb_repetitions !== undefined && avenant.duree_data.nb_repetitions > 0 && (
<div>Répétitions : {avenant.duree_data.nb_repetitions}</div>
)}
{/* Pour les techniciens */}
{avenant.duree_data.nb_heures !== undefined && avenant.duree_data.nb_heures > 0 && (
<div>Nombre d'heures : {avenant.duree_data.nb_heures}h</div>
)}
{/* Dates de travail */}
{Array.isArray(avenant.duree_data.dates_representations) && avenant.duree_data.dates_representations.length > 0 && (
<div>
<div className="font-medium mt-2">Dates de représentations :</div>
<div className="flex flex-wrap gap-2 mt-1">
{avenant.duree_data.dates_representations.map((d: any, idx: number) => (
<div key={idx} className="inline-flex items-center gap-2 px-2 py-1 bg-blue-100 rounded text-xs">
<span className="font-medium">{formatDate(d.date)}</span>
{d.quantity && d.quantity > 0 && (
<span className="text-blue-700">({d.quantity})</span>
)}
</div>
))}
</div>
</div>
)}
{Array.isArray(avenant.duree_data.dates_repetitions) && avenant.duree_data.dates_repetitions.length > 0 && (
<div>
<div className="font-medium mt-2">Dates de répétitions :</div>
<div className="flex flex-wrap gap-2 mt-1">
{avenant.duree_data.dates_repetitions.map((d: any, idx: number) => (
<div key={idx} className="inline-flex items-center gap-2 px-2 py-1 bg-purple-100 rounded text-xs">
<span className="font-medium">{formatDate(d.date)}</span>
{d.quantity && d.quantity > 0 && (
<span className="text-purple-700">({d.quantity})</span>
)}
</div>
))}
</div>
</div>
)}
{/* Jours de travail (techniciens) */}
{avenant.duree_data.jours_travail && (
<div>
<div className="font-medium mt-2">Jours de travail :</div>
{Array.isArray(avenant.duree_data.jours_travail) ? (
<div className="flex flex-wrap gap-2 mt-1">
{avenant.duree_data.jours_travail.map((d: any, idx: number) => (
<div key={idx} className="inline-flex items-center gap-2 px-2 py-1 bg-slate-100 rounded text-xs">
<span className="font-medium">{formatDate(d.date)}</span>
{d.quantity && d.quantity > 0 && (
<span className="text-slate-600">({d.quantity}h)</span>
)}
</div>
))}
</div>
) : (
<div className="text-xs">{avenant.duree_data.jours_travail}</div>
)}
</div>
)}
</div>
)}
{element === "lieu_horaire" && avenant.lieu_horaire_data && (
<div className="text-sm text-slate-600 space-y-1">
{avenant.lieu_horaire_data.lieu && (
<div>Lieu : {avenant.lieu_horaire_data.lieu}</div>
)}
</div>
)}
{element === "remuneration" && avenant.remuneration_data && (
<div className="text-sm text-slate-600 space-y-1">
{avenant.remuneration_data.gross_pay && (
<div>Salaire brut : {avenant.remuneration_data.gross_pay} </div>
)}
{avenant.remuneration_data.type_salaire && (
<div>Type : {avenant.remuneration_data.type_salaire}</div>
)}
{avenant.remuneration_data.precisions_salaire && (
<div>Précisions : {avenant.remuneration_data.precisions_salaire}</div>
)}
</div>
)}
</div>
))}
</div>
</div>
{/* PDF */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<h2 className="font-semibold text-slate-900 mb-4">Document signé</h2>
<div className="flex items-start gap-4 p-4 bg-slate-50 rounded-lg border">
<div className="flex-shrink-0 w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center">
<FileText className="h-6 w-6 text-indigo-600" />
</div>
<div className="flex-1 min-w-0">
<div className="font-medium text-slate-900">
{avenant.pdf_s3_key ? `Avenant ${avenant.numero_avenant}.pdf` : "PDF non généré"}
</div>
<div className="text-sm text-slate-500 mt-1">
{avenant.pdf_s3_key ? "Document stocké sur AWS S3" : "Aucun document disponible"}
</div>
{avenant.pdf_s3_key && (
<div className="text-xs text-slate-400 mt-1 font-mono truncate">
{avenant.pdf_s3_key}
</div>
)}
</div>
<div className="flex-shrink-0 flex gap-2">
{loadingPdf ? (
<div className="px-4 py-2 bg-slate-100 text-slate-500 rounded-lg">
Chargement...
</div>
) : pdfUrl ? (
<>
<a
href={pdfUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
>
<Download className="h-4 w-4" />
Télécharger
</a>
<button
onClick={handleRegeneratePdf}
disabled={isRegeneratingPdf}
className="inline-flex items-center gap-2 px-4 py-2 border border-indigo-300 text-indigo-700 rounded-lg hover:bg-indigo-50 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<RefreshCw className={`h-4 w-4 ${isRegeneratingPdf ? "animate-spin" : ""}`} />
{isRegeneratingPdf ? "Génération..." : "Regénérer"}
</button>
</>
) : (
<button
onClick={handleRegeneratePdf}
disabled={isRegeneratingPdf}
className="inline-flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
<RefreshCw className={`h-4 w-4 ${isRegeneratingPdf ? "animate-spin" : ""}`} />
{isRegeneratingPdf ? "Génération..." : "Générer le PDF"}
</button>
)}
</div>
</div>
</div>
{/* Actions */}
<div className="bg-white rounded-xl border shadow-sm p-6">
<div className="flex items-center gap-3">
<button
onClick={() => router.push("/staff/avenants")}
className="px-6 py-3 text-slate-700 hover:bg-slate-100 rounded-lg transition-colors font-medium"
>
Retour à la liste
</button>
{avenant.statut === "draft" && (
<>
<button
onClick={() => {
if (!avenant.pdf_s3_key) {
alert("Vous devez d'abord générer le PDF avant de l'envoyer en signature.");
return;
}
setShowSendSignatureModal(true);
}}
disabled={isSendingSignature}
className="inline-flex items-center gap-2 px-6 py-3 bg-orange-600 text-white rounded-lg hover:bg-orange-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
>
<Send className="h-4 w-4" />
Envoyer pour signature
</button>
<button className="px-6 py-3 border border-slate-300 text-slate-700 rounded-lg hover:bg-slate-50 transition-colors font-medium">
Modifier
</button>
</>
)}
</div>
</div>
{/* Modale de suppression */}
<DeleteAvenantModal
isOpen={showDeleteModal}
onClose={() => setShowDeleteModal(false)}
onConfirm={handleDelete}
numeroAvenant={avenant.numero_avenant}
isDeleting={isDeleting}
/>
{/* Modale d'envoi en signature */}
<SendSignatureModal
isOpen={showSendSignatureModal}
onClose={() => {
setShowSendSignatureModal(false);
setSendSignatureSuccess(false);
}}
onConfirm={handleSendForSignature}
isSending={isSendingSignature}
success={sendSignatureSuccess}
avenantData={{
numero_avenant: avenant.numero_avenant,
contractReference: contract?.contract_number || "N/A",
employeeName: contract?.salaries ? `${contract.salaries.prenom} ${contract.salaries.nom}` : "N/A",
employerEmail: contract?.organizations?.organization_details?.email_signature || "N/A",
employeeEmail: contract?.salaries?.adresse_mail || "N/A",
}}
/>
{/* Modale de changement de statut */}
<ChangeStatusModal
isOpen={showChangeStatusModal}
onClose={() => setShowChangeStatusModal(false)}
onConfirm={handleChangeStatus}
currentStatus={avenant.statut}
isChanging={isChangingStatus}
numeroAvenant={avenant.numero_avenant}
/>
{/* Modale de mise à jour du statut de signature */}
<UpdateSignatureStatusModal
isOpen={showUpdateSignatureModal}
onClose={() => setShowUpdateSignatureModal(false)}
onConfirm={handleUpdateSignatureStatus}
currentSignatureStatus={avenant.signature_status}
isUpdating={isUpdatingSignature}
numeroAvenant={avenant.numero_avenant}
/>
</div>
);
}