Sage100/src/components/page/client/ClientContactsList.tsx
2026-01-20 11:05:50 +03:00

207 lines
No EOL
6.4 KiB
TypeScript

import React from "react";
import { Plus, User, Mail, Phone, Building2, Edit, Trash2 } from "lucide-react";
import PrimaryButton_v2 from "@/components/PrimaryButton_v2";
import { Contacts } from "@/types/clientType";
// ============================================
// TYPES
// ============================================
interface ClientContactsListProps {
contacts: Contacts[];
onCreateContact: () => void;
onEditContact: (contact: Contacts) => void;
onDeleteContact?: (contactId: string | number) => void;
showDeleteButton?: boolean;
}
// ============================================
// SOUS-COMPOSANTS
// ============================================
const EmptyState: React.FC = () => (
<div className="text-center py-12 bg-white dark:bg-gray-950 rounded-2xl border border-dashed border-gray-200 dark:border-gray-800">
<User className="w-12 h-12 text-gray-300 mx-auto mb-3" />
<p className="text-gray-500 font-medium">Aucun contact enregistré</p>
<p className="text-sm text-gray-400 mt-1">
Cliquez sur "Ajouter un contact" pour commencer
</p>
</div>
);
const ContactAvatar: React.FC<{ nom: string; prenom: string }> = ({ nom, prenom }) => (
<div className="w-10 h-10 rounded-full bg-gray-100 dark:bg-gray-800 flex items-center justify-center text-gray-600 dark:text-gray-300 font-bold">
{prenom?.[0] || ""}{nom?.[0] || ""}
</div>
);
const DefaultBadge: React.FC = () => (
<span className="px-2 py-0.5 bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300 text-[10px] font-bold uppercase tracking-wider rounded-full border border-green-200 dark:border-green-800">
Défaut
</span>
);
interface ContactInfoRowProps {
icon: React.ElementType;
value: string;
href?: string;
type?: "email" | "tel";
}
const ContactInfoRow: React.FC<ContactInfoRowProps> = ({ icon: Icon, value, href, type }) => {
const content = (
<>
<Icon className="w-4 h-4" />
{value}
</>
);
if (href) {
return (
<a
href={type === "email" ? `mailto:${href}` : type === "tel" ? `tel:${href}` : href}
className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400 hover:text-[#007E45] transition-colors"
>
{content}
</a>
);
}
return (
<div className="flex items-center gap-2 text-sm text-gray-600 dark:text-gray-400">
{content}
</div>
);
};
interface ContactCardProps {
contact: Contacts;
onEdit: (contact: Contacts) => void;
onDelete?: (contactId: string | number) => void;
showDeleteButton?: boolean;
}
const ContactCard: React.FC<ContactCardProps> = ({
contact,
onEdit,
onDelete,
showDeleteButton = false,
}) => (
<div className="bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 rounded-xl p-5 hover:shadow-md transition-shadow relative group">
{/* Header */}
<div className="flex justify-between items-start mb-4">
<div className="flex items-center gap-3">
<ContactAvatar nom={contact.nom} prenom={contact.prenom} />
<div>
<h4 className="font-bold text-gray-900 dark:text-white">
{contact.prenom} {contact.nom}
</h4>
<p className="text-xs text-gray-500">
{contact.fonction || "Pas de poste défini"}
</p>
</div>
</div>
{contact.est_defaut && <DefaultBadge />}
</div>
{/* Contact Info */}
<div className="space-y-2 mb-4">
{contact.email && (
<ContactInfoRow
icon={Mail}
value={contact.email}
href={contact.email}
type="email"
/>
)}
{contact.telephone && (
<ContactInfoRow
icon={Phone}
value={contact.telephone}
href={contact.telephone}
type="tel"
/>
)}
<ContactInfoRow
icon={Building2}
value={contact.fonction || "Non spécifié"}
/>
</div>
{/* Actions */}
<div className="pt-4 border-t border-gray-100 dark:border-gray-800 flex justify-end gap-2">
<button
onClick={() => onEdit(contact)}
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded-lg text-gray-400 hover:text-blue-500 transition-colors"
title="Modifier"
>
<Edit className="w-4 h-4" />
</button>
{showDeleteButton && onDelete && contact.numero && (
<button
onClick={() => onDelete(contact.numero!)}
className="p-2 hover:bg-red-50 dark:hover:bg-red-900/20 rounded-lg text-gray-400 hover:text-red-500 transition-colors"
title="Supprimer"
>
<Trash2 className="w-4 h-4" />
</button>
)}
</div>
</div>
);
// ============================================
// COMPOSANT PRINCIPAL
// ============================================
const ClientContactsList: React.FC<ClientContactsListProps> = ({
contacts,
onCreateContact,
onEditContact,
onDeleteContact,
showDeleteButton = false,
}) => {
const contactCount = contacts?.length || 0;
return (
<div className="space-y-6">
{/* Header */}
<div className="flex justify-between items-center">
<h3 className="font-bold text-gray-900 dark:text-white">
Liste des contacts ({contactCount})
</h3>
<PrimaryButton_v2 icon={Plus} onClick={onCreateContact}>
Ajouter un contact
</PrimaryButton_v2>
</div>
{/* Content */}
{contactCount === 0 ? (
<EmptyState />
) : (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{contacts?.map((contact, index) => (
<ContactCard
key={index}
contact={contact}
onEdit={onEditContact}
onDelete={onDeleteContact}
showDeleteButton={showDeleteButton}
/>
))}
</div>
)}
</div>
);
};
export default ClientContactsList;
// Export des sous-composants si besoin
export {
EmptyState,
ContactAvatar,
DefaultBadge,
ContactInfoRow,
ContactCard,
};