import { useState } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; import { useAuthUnified } from "@/hooks/useAuthUnified"; import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; import { isUnauthorizedError } from "@/lib/authUtils"; import { Plus, Search, Building, Phone, Edit, Trash2, Package, Truck, CheckCircle, Clock } from "lucide-react"; import type { Supplier } from "@shared/schema"; export default function Suppliers() { const { user } = useAuthUnified(); const { toast } = useToast(); const queryClient = useQueryClient(); const [searchTerm, setSearchTerm] = useState(""); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [selectedSupplier, setSelectedSupplier] = useState(null); const [formData, setFormData] = useState({ name: "", contact: "", phone: "", hasDlc: false, automaticReconciliation: false, }); const { data: suppliers = [], isLoading } = useQuery({ queryKey: ['/api/suppliers'], }); const { data: orders = [] } = useQuery({ queryKey: ['/api/orders'], }); const { data: deliveries = [] } = useQuery({ queryKey: ['/api/deliveries'], }); const createMutation = useMutation({ mutationFn: async (data: any) => { console.log('🚚 Frontend: Creating supplier with data:', data); const result = await apiRequest("/api/suppliers", "POST", data); console.log('🚚 Frontend: Supplier creation result:', result); return result; }, onSuccess: () => { toast({ title: "Succès", description: "Fournisseur créé avec succès", }); queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); setShowCreateModal(false); resetForm(); }, onError: (error) => { if (isUnauthorizedError(error)) { toast({ title: "Non autorisé", description: "Vous êtes déconnecté. Reconnexion...", variant: "destructive", }); setTimeout(() => { window.location.href = "/api/login"; }, 500); return; } toast({ title: "Erreur", description: "Impossible de créer le fournisseur", variant: "destructive", }); }, }); const updateMutation = useMutation({ mutationFn: async (data: any) => { console.log('🔧 Frontend: Updating supplier with data:', data); const result = await apiRequest(`/api/suppliers/${selectedSupplier?.id}`, "PUT", data); console.log('🔧 Frontend: Supplier update result:', result); return result; }, onMutate: async (newData) => { // Mise à jour optimiste - mettre à jour l'interface immédiatement console.log('🚀 Frontend: Optimistic update starting...'); await queryClient.cancelQueries({ queryKey: ['/api/suppliers'] }); const previousSuppliers = queryClient.getQueryData(['/api/suppliers']); if (previousSuppliers && selectedSupplier) { const updatedSuppliers = (previousSuppliers as any[]).map(supplier => supplier.id === selectedSupplier.id ? { ...supplier, ...newData, updatedAt: new Date().toISOString() } : supplier ); queryClient.setQueryData(['/api/suppliers'], updatedSuppliers); console.log('✅ Frontend: Optimistic update applied'); } return { previousSuppliers }; }, onError: (error, newData, context) => { // Rollback en cas d'erreur console.log('⚠️ Frontend: Rolling back optimistic update due to error'); if (context?.previousSuppliers) { queryClient.setQueryData(['/api/suppliers'], context.previousSuppliers); } if (isUnauthorizedError(error)) { toast({ title: "Non autorisé", description: "Vous êtes déconnecté. Reconnexion...", variant: "destructive", }); setTimeout(() => { window.location.href = "/api/login"; }, 500); return; } toast({ title: "Erreur", description: "Impossible de modifier le fournisseur", variant: "destructive", }); }, onSuccess: () => { toast({ title: "Succès", description: "Fournisseur modifié avec succès", }); queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); setShowEditModal(false); setSelectedSupplier(null); resetForm(); }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); }, }); const deleteMutation = useMutation({ mutationFn: async (id: number) => { await apiRequest(`/api/suppliers/${id}`, "DELETE"); }, onSuccess: () => { toast({ title: "Succès", description: "Fournisseur supprimé avec succès", }); queryClient.invalidateQueries({ queryKey: ['/api/suppliers'] }); }, onError: (error) => { if (isUnauthorizedError(error)) { toast({ title: "Non autorisé", description: "Vous êtes déconnecté. Reconnexion...", variant: "destructive", }); setTimeout(() => { window.location.href = "/api/login"; }, 500); return; } toast({ title: "Erreur", description: "Impossible de supprimer le fournisseur", variant: "destructive", }); }, }); const resetForm = () => { setFormData({ name: "", contact: "", phone: "", hasDlc: false, automaticReconciliation: false, }); }; const handleChange = (field: string, value: any) => { setFormData(prev => ({ ...prev, [field]: value })); }; const handleCreate = () => { if (user?.role !== 'admin') { toast({ title: "Accès refusé", description: "Seuls les administrateurs peuvent créer des fournisseurs", variant: "destructive", }); return; } resetForm(); setShowCreateModal(true); }; const handleEdit = (supplier: Supplier) => { if (user?.role !== 'admin') { toast({ title: "Accès refusé", description: "Seuls les administrateurs peuvent modifier des fournisseurs", variant: "destructive", }); return; } setSelectedSupplier(supplier); setFormData({ name: supplier.name || "", contact: supplier.contact || "", phone: supplier.phone || "", hasDlc: supplier.hasDlc || false, automaticReconciliation: supplier.automaticReconciliation || false, }); setShowEditModal(true); }; const handleDelete = (supplier: Supplier) => { if (user?.role !== 'admin') { toast({ title: "Accès refusé", description: "Seuls les administrateurs peuvent supprimer des fournisseurs", variant: "destructive", }); return; } if (confirm(`Êtes-vous sûr de vouloir supprimer le fournisseur "${supplier.name}" ?`)) { deleteMutation.mutate(supplier.id); } }; const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (selectedSupplier) { updateMutation.mutate(formData); } else { createMutation.mutate(formData); } }; const filteredSuppliers = suppliers.filter(supplier => supplier.name.toLowerCase().includes(searchTerm.toLowerCase()) ); const getSupplierStats = (supplierId: number) => { const supplierOrders = orders.filter((order: any) => order.supplierId === supplierId); const supplierDeliveries = deliveries.filter((delivery: any) => delivery.supplierId === supplierId); const deliveredCount = supplierDeliveries.filter((delivery: any) => delivery.status === 'delivered').length; return { orders: supplierOrders.length, deliveries: supplierDeliveries.length, delivered: deliveredCount, }; }; if (isLoading) { return (
{[1, 2, 3].map(i => (
))}
); } return (

Fournisseurs

Gestion des fournisseurs et partenaires

{user?.role === 'admin' && ( )}
setSearchTerm(e.target.value)} className="pl-10 border border-gray-300 shadow-sm" />
{filteredSuppliers.length === 0 ? (

{searchTerm ? "Aucun fournisseur trouvé" : "Aucun fournisseur"}

{searchTerm ? "Aucun fournisseur ne correspond à votre recherche" : "Commencez par créer votre premier fournisseur" }

{!searchTerm && user?.role === 'admin' && ( )}
) : (
{filteredSuppliers.map((supplier) => { const stats = getSupplierStats(supplier.id); return (

{supplier.name}

#{supplier.id}

{user?.role === 'admin' && (
)}
{supplier.contact && (
{supplier.contact}
)} {supplier.phone && (
{supplier.phone}
)}
{supplier.hasDlc && (
DLC
)} {supplier.automaticReconciliation && (
Auto-rapprochement
)}
{!supplier.hasDlc && !supplier.automaticReconciliation && (
Aucune option activée
)}
{stats.orders}

Commandes

{stats.deliveries}

Livraisons

{stats.deliveries > 0 && (

{stats.delivered} livrées ({Math.round((stats.delivered / stats.deliveries) * 100)}%)

)}
); })}
)}
{/* Create/Edit Modal */} { setShowCreateModal(false); setShowEditModal(false); setSelectedSupplier(null); resetForm(); }}> {selectedSupplier ? 'Modifier' : 'Nouveau'} Fournisseur

{selectedSupplier ? 'Modifier les informations du fournisseur' : 'Créer un nouveau fournisseur'}

handleChange('name', e.target.value)} placeholder="Nom du fournisseur" required />
handleChange('contact', e.target.value)} placeholder="Nom du contact" />
handleChange('phone', e.target.value)} placeholder="Numéro de téléphone" />
handleChange('hasDlc', checked === true)} />
handleChange('automaticReconciliation', checked === true)} />
); }