espace-paie-odentas/components/staff/BulkESignConfirmModal.tsx

187 lines
7.1 KiB
TypeScript

// components/staff/BulkESignConfirmModal.tsx
"use client";
import React, { useState, useEffect } from "react";
import { X, FileSignature, AlertTriangle, Mail } from "lucide-react";
type Contract = {
id: string;
contract_number?: string | null;
employee_name?: string | null;
employee_id?: string | null;
org_id?: string | null;
structure?: string | null;
salaries?: {
salarie?: string | null;
nom?: string | null;
prenom?: string | null;
adresse_mail?: string | null;
} | null;
};
type BulkESignConfirmModalProps = {
isOpen: boolean;
onClose: () => void;
onConfirm: (sendNotification: boolean) => void;
contractCount: number;
selectedContracts?: Contract[];
};
export default function BulkESignConfirmModal({
isOpen,
onClose,
onConfirm,
contractCount,
selectedContracts = []
}: BulkESignConfirmModalProps) {
const [sendNotification, setSendNotification] = useState(true);
const [employerEmails, setEmployerEmails] = useState<Record<string, string>>({});
// Charger les emails au montage
useEffect(() => {
if (!isOpen || selectedContracts.length === 0) return;
const fetchEmails = async () => {
const orgIds = [...new Set(selectedContracts.map(c => c.org_id).filter(Boolean))];
const emails: Record<string, string> = {};
try {
const response = await fetch('/api/staff/organizations/emails', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ org_ids: orgIds }),
});
if (response.ok) {
const data = await response.json();
// data est un array de { org_id, email_signature }
data.forEach((org: any) => {
if (org.org_id && org.email_signature) {
emails[org.org_id] = org.email_signature;
}
});
}
} catch (error) {
console.error('Erreur lors de la récupération des emails de signature:', error);
}
setEmployerEmails(emails);
};
fetchEmails();
}, [isOpen, selectedContracts]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-6 w-full max-w-2xl max-h-[90vh] overflow-y-auto">
{/* Header */}
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<FileSignature className="size-5 text-indigo-600" />
<h2 className="text-lg font-semibold">Confirmer l'envoi des signatures</h2>
</div>
<button
onClick={onClose}
className="p-1 hover:bg-gray-100 rounded"
>
<X className="size-5" />
</button>
</div>
{/* Warning Message */}
<div className="mb-4 p-3 bg-amber-50 border border-amber-200 rounded-lg flex gap-3">
<AlertTriangle className="size-5 text-amber-600 flex-shrink-0 mt-0.5" />
<div className="text-sm text-amber-800">
<p className="font-medium mb-1">Attention</p>
<p>
Vous êtes sur le point de créer les signatures électroniques pour{" "}
<strong>{contractCount}</strong> contrat{contractCount > 1 ? 's' : ''}.
</p>
</div>
</div>
{/* Info */}
<div className="mb-4 text-sm text-gray-600 space-y-2">
<p className="font-medium">Cette action va :</p>
<ul className="list-disc list-inside space-y-1 ml-2">
<li>Créer une demande de signature électronique pour chaque contrat</li>
{sendNotification && <li className="text-indigo-600 font-medium">Envoyer un email récapitulatif au client</li>}
</ul>
<p className="mt-3 font-medium text-gray-700">
Assurez-vous que tous les contrats ont un PDF généré et que les salariés ont un email renseigné.
</p>
</div>
{/* Contracts Summary with Emails */}
{selectedContracts.length > 0 && (
<div className="mb-6 p-4 bg-indigo-50 border border-indigo-200 rounded-lg">
<div className="flex items-center gap-2 mb-3">
<Mail className="size-4 text-indigo-600" />
<p className="text-sm font-medium text-indigo-900">Récapitulatif des destinataires</p>
</div>
{/* Contracts List */}
<div className="space-y-2 max-h-48 overflow-y-auto">
{selectedContracts.map((contract) => {
const employeeEmail = contract.salaries?.adresse_mail;
const employerEmail = employerEmails[contract.org_id as string];
return (
<div key={contract.id} className="p-2 bg-white rounded border border-indigo-100 text-xs">
<p className="font-medium text-gray-900">
{contract.contract_number && `[${contract.contract_number}]`} {contract.employee_name || contract.salaries?.salarie || ''}
</p>
<p className="text-gray-600 mt-1">
Salarié : <span className={employeeEmail ? "text-indigo-600 font-mono" : "text-orange-600"}>{employeeEmail || "Email non renseigné"}</span>
</p>
<p className="text-gray-600">
Employeur (signature) : <span className={employerEmail ? "text-indigo-600 font-mono" : "text-orange-600"}>{employerEmail || "Email signature non renseigné"}</span>
</p>
</div>
);
})}
</div>
</div>
)}
{/* Option: Envoyer notification */}
<div className="mb-6 p-3 bg-gray-50 border border-gray-200 rounded-lg">
<label className="flex items-start gap-3 cursor-pointer">
<input
type="checkbox"
checked={sendNotification}
onChange={(e) => setSendNotification(e.target.checked)}
className="mt-0.5 size-4 text-indigo-600 rounded focus:ring-indigo-500"
/>
<div className="flex-1">
<span className="text-sm font-medium text-gray-900">
Envoyer un email récapitulatif au client
</span>
<p className="text-xs text-gray-500 mt-1">
Si décoché, les signatures seront créées dans DocuSeal mais aucun email de notification groupée ne sera envoyé à l'employeur.
</p>
</div>
</label>
</div>
{/* Actions */}
<div className="flex justify-end gap-2">
<button
onClick={onClose}
className="px-4 py-2 text-sm text-gray-600 border border-gray-300 rounded hover:bg-gray-50"
>
Annuler
</button>
<button
onClick={() => onConfirm(sendNotification)}
className="px-4 py-2 text-sm bg-indigo-600 text-white rounded hover:bg-indigo-700"
>
Confirmer et envoyer
</button>
</div>
</div>
</div>
);
}