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 { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Pagination, usePagination } from "@/components/ui/pagination"; import { useAuthUnified } from "@/hooks/useAuthUnified"; import { useStore } from "@/components/Layout"; import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; import { isUnauthorizedError } from "@/lib/authUtils"; import { Plus, Search, Filter, Package, Calendar, Eye, Edit, Trash2, Building, User } from "lucide-react"; import { safeFormat } from "@/lib/dateUtils"; import CreateOrderModal from "@/components/modals/CreateOrderModal"; import EditOrderModal from "@/components/modals/EditOrderModal"; import OrderDetailModal from "@/components/modals/OrderDetailModal"; import ConfirmDeleteModal from "@/components/modals/ConfirmDeleteModal"; import { usePermissions } from "@shared/permissions"; import type { OrderWithRelations } from "@shared/schema"; export default function Orders() { const { user } = useAuthUnified(); const { selectedStoreId } = useStore(); const { toast } = useToast(); const queryClient = useQueryClient(); const permissions = usePermissions(user?.role); // Redirection pour les employés if (user?.role === 'employee') { return (

Accès restreint
Seuls les managers et administrateurs peuvent accéder à la page des commandes.

); } const [searchTerm, setSearchTerm] = useState(""); const [statusFilter, setStatusFilter] = useState("all"); const [showCreateModal, setShowCreateModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [showDetailModal, setShowDetailModal] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [selectedOrder, setSelectedOrder] = useState(null); const [orderToDelete, setOrderToDelete] = useState(null); // Construire l'URL pour l'historique complet sans filtrage par date const ordersUrl = `/api/orders${selectedStoreId && user?.role === 'admin' ? `?storeId=${selectedStoreId}` : ''}`; const { data: ordersData = [], isLoading } = useQuery({ queryKey: [ordersUrl, selectedStoreId], queryFn: async () => { const response = await fetch(ordersUrl, { credentials: 'include' }); if (!response.ok) { throw new Error('Failed to fetch orders'); } const data = await response.json(); console.log('📦 Orders received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items', data.slice(0, 2)); console.log('📦 Sample order data:', data[0]); return Array.isArray(data) ? data : []; }, }); // Production Bug Fix: Ensure array safety for all data operations const orders = Array.isArray(ordersData) ? ordersData : []; console.log('📦 Orders Debug:', { isLoading, ordersCount: orders?.length, orders: orders?.slice(0, 2), selectedStoreId, ordersUrl }); const { data: groupsData = [] } = useQuery({ queryKey: ['/api/groups'], }); const groups = Array.isArray(groupsData) ? groupsData : []; const deleteMutation = useMutation({ mutationFn: async (id: number) => { console.log('🗑️ Deleting order:', id); await apiRequest(`/api/orders/${id}`, "DELETE"); }, onSuccess: () => { console.log('✅ Order deleted successfully, invalidating cache...'); toast({ title: "Succès", description: "Commande supprimée avec succès", }); console.log('🗑️ Order deleted, clearing ALL cache to avoid inconsistencies:', { ordersUrl, selectedStoreId }); // Sauvegarder le selectedStoreId avant le nettoyage if (selectedStoreId) { localStorage.setItem('selectedStoreId', selectedStoreId.toString()); } // SOLUTION HYBRIDE : Invalidation sélective pour éviter perte storeId console.log('🧹 Using selective invalidation to preserve storeId context...'); // Invalidation ciblée sans clear() pour préserver le contexte queryClient.invalidateQueries({ predicate: (query) => { const key = query.queryKey[0]?.toString() || ''; return key.includes('/api/orders') || key.includes('/api/deliveries'); } }); // Force refetch pour garantir synchronisation immédiate queryClient.refetchQueries({ predicate: (query) => { const key = query.queryKey[0]?.toString() || ''; return key.includes('/api/orders') || key.includes('/api/deliveries'); } }); }, 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 la commande", variant: "destructive", }); }, }); const filteredOrders = Array.isArray(orders) ? orders.filter(order => { console.log('🔍 Filtering order:', order.id, { searchTerm, statusFilter }); const matchesSearch = order.supplier?.name.toLowerCase().includes(searchTerm.toLowerCase()) || order.group?.name.toLowerCase().includes(searchTerm.toLowerCase()) || order.notes?.toLowerCase().includes(searchTerm.toLowerCase()); const matchesStatus = statusFilter === "all" || order.status === statusFilter; return matchesSearch && matchesStatus; }) : []; // Pagination const { currentPage, setCurrentPage, itemsPerPage, setItemsPerPage, totalPages, paginatedData: paginatedOrders, totalItems } = usePagination(filteredOrders, 20); const getStatusBadge = (status: string) => { switch (status) { case 'pending': return En attente; case 'planned': return Planifié; case 'delivered': return Livré; default: return {status}; } }; const handleViewOrder = (order: OrderWithRelations) => { setSelectedOrder({ ...order, type: 'order' }); setShowDetailModal(true); }; const handleEditOrder = (order: OrderWithRelations) => { setSelectedOrder(order); setShowEditModal(true); }; const handleDeleteOrder = (order: OrderWithRelations) => { setOrderToDelete(order); setShowDeleteModal(true); }; const confirmDeleteOrder = () => { if (orderToDelete) { deleteMutation.mutate(orderToDelete.id); setShowDeleteModal(false); setOrderToDelete(null); } }; const canCreate = permissions.canCreate('orders'); const canEdit = permissions.canEdit('orders'); const canDelete = permissions.canDelete('orders'); return (
{/* Header */}

Gestion des Commandes

{filteredOrders.length} commande{filteredOrders.length !== 1 ? 's' : ''}

{canCreate && ( )}
{/* Filters */}
setSearchTerm(e.target.value)} className="pl-10 border border-gray-300 shadow-sm" />
{/* Orders List */}
{isLoading ? (
) : filteredOrders.length === 0 ? (

Aucune commande trouvée

{searchTerm || statusFilter !== "all" ? "Aucune commande ne correspond à vos critères de recherche." : "Vous n'avez pas encore de commandes. Créez votre première commande pour commencer."}

{canCreate && !searchTerm && statusFilter === "all" && ( )}
) : (
{paginatedOrders.map((order) => ( ))}
Fournisseur Groupe Date prévue Statut Créé par Actions
{order.supplier?.name}
#{order.id}
{order.group?.name}
{safeFormat(order.plannedDate, 'dd MMM yyyy')}
{getStatusBadge(order.status)}
{order.creator?.firstName} {order.creator?.lastName}
{canEdit && ( )} {canDelete && ( )}
{/* Pagination */}
)}
{/* Modals */} {showCreateModal && ( setShowCreateModal(false)} selectedDate={null} /> )} {showEditModal && selectedOrder && ( setShowEditModal(false)} order={selectedOrder} /> )} {showDetailModal && selectedOrder && ( setShowDetailModal(false)} item={selectedOrder} /> )} {/* Modal de confirmation de suppression */} { setShowDeleteModal(false); setOrderToDelete(null); }} onConfirm={confirmDeleteOrder} title="Supprimer la commande" description="Êtes-vous sûr de vouloir supprimer cette commande ?" itemName={orderToDelete ? `${orderToDelete.supplier?.name} - ${safeFormat(orderToDelete.plannedDate, 'dd/MM/yyyy')}` : undefined} isLoading={deleteMutation.isPending} />
); }