import { format, startOfMonth, endOfMonth, eachDayOfInterval, isSameDay, isSameMonth, isToday } from "date-fns"; import { fr } from "date-fns/locale"; import { safeDate } from "@/lib/dateUtils"; import { Plus, Check, MoreHorizontal, Package } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"; import { useState } from "react"; import type { OrderWithRelations, DeliveryWithRelations } from "@shared/schema"; interface CalendarGridProps { currentDate: Date; orders: OrderWithRelations[]; deliveries: DeliveryWithRelations[]; publicities: any[]; selectedStoreId: number | null; userGroups: any[]; onDateClick: (date: Date) => void; onItemClick: (item: any, type: 'order' | 'delivery') => void; } // Composant pour afficher un élément (commande ou livraison) - VERSION PRODUCTION function CalendarItem({ item, type, onItemClick }: { item: any, type: 'order' | 'delivery', onItemClick: (item: any, type: 'order' | 'delivery') => void }) { const formatQuantity = (quantity: number, unit: string) => { return `${quantity}${unit === 'palettes' ? 'P' : 'C'}`; }; if (type === 'order') { const getOrderStyle = () => { switch (item.status) { case 'delivered': return 'bg-gray-400 text-white shadow-sm border-l-4 border-gray-500'; case 'planned': return 'bg-yellow-300 text-gray-800 shadow-sm border-l-4 border-yellow-500 font-medium'; default: return 'bg-blue-300 text-gray-800 shadow-sm border-l-4 border-blue-500'; } }; return (
{ e.stopPropagation(); onItemClick(item, 'order'); }} style={{marginBottom: '2px', display: 'block', width: '100%'}} >
{item.supplier?.name || 'Commande'}
{item.status === 'planned' && (
)} {item.status === 'delivered' && ( )}
); } // Livraison const getDeliveryStyle = () => { switch (item.status) { case 'delivered': return 'bg-gray-400 text-white shadow-sm border-l-4 border-gray-500'; case 'pending': return 'bg-green-300 text-gray-800 shadow-sm border-l-4 border-green-500'; default: return 'bg-green-300 text-gray-800 shadow-sm border-l-4 border-green-500'; } }; return (
{ e.stopPropagation(); onItemClick(item, 'delivery'); }} style={{marginBottom: '2px', display: 'block', width: '100%'}} >
{item.supplier?.name || 'Livraison'} - {formatQuantity(item.quantity, item.unit)}
{item.status === 'pending' && (
)} {item.status === 'delivered' && ( )}
); } // Composant pour gérer l'overflow avec modal - VERSION PRODUCTION function DayItemsContainer({ dayOrders, dayDeliveries, onItemClick }: { dayOrders: any[], dayDeliveries: any[], onItemClick: (item: any, type: 'order' | 'delivery') => void }) { const [isOpen, setIsOpen] = useState(false); const MAX_VISIBLE_ITEMS = 4; // PRODUCTION : TOUJOURS 4 ÉLÉMENTS const totalItems = dayOrders.length + dayDeliveries.length; if (totalItems === 0) return null; // Combiner tous les éléments avec leur type const allItems = [ ...dayOrders.map(order => ({ ...order, itemType: 'order' as const })), ...dayDeliveries.map(delivery => ({ ...delivery, itemType: 'delivery' as const })) ]; const visibleItems = allItems.slice(0, MAX_VISIBLE_ITEMS); const hiddenCount = Math.max(0, totalItems - MAX_VISIBLE_ITEMS); return (
{/* Éléments visibles */} {visibleItems.map((item, index) => ( ))} {/* Badge "+X autres" avec modal - PRODUCTION */} {hiddenCount > 0 && ( Éléments du jour ({totalItems})
{allItems.map((item, index) => (
{ onItemClick(clickedItem, type); setIsOpen(false); }} />
))}
)}
); } export default function CalendarGrid({ currentDate, orders, deliveries, publicities, selectedStoreId, userGroups, onDateClick, onItemClick }: CalendarGridProps) { const weekDays = ['LUN', 'MAR', 'MER', 'JEU', 'VEN', 'SAM', 'DIM']; // Generate calendar days const monthStart = startOfMonth(currentDate); const monthEnd = endOfMonth(currentDate); const calendarDays = eachDayOfInterval({ start: monthStart, end: monthEnd }); // Calculate the number of days to show before the month starts (to align with Monday) const startPadding = (monthStart.getDay() + 6) % 7; // Convert Sunday=0 to Monday=0 format const paddingDays = Array.from({ length: startPadding }, (_, i) => { const date = new Date(monthStart); date.setDate(date.getDate() - startPadding + i); return date; }); const paddedDays = [...paddingDays, ...calendarDays]; // Filter data based on selected store const filteredOrders = selectedStoreId ? orders.filter(order => order.groupId === selectedStoreId) : orders; const filteredDeliveries = selectedStoreId ? deliveries.filter(delivery => delivery.groupId === selectedStoreId) : deliveries; const getItemsForDate = (date: Date) => { const dayOrders = filteredOrders.filter(order => { const orderDate = safeDate(order.scheduledDate || order.deliveredDate || order.createdAt); return orderDate && isSameDay(orderDate, date); }); const dayDeliveries = filteredDeliveries.filter(delivery => { const deliveryDate = safeDate(delivery.scheduledDate || delivery.deliveredDate || delivery.createdAt); return deliveryDate && isSameDay(deliveryDate, date); }); return { orders: dayOrders, deliveries: dayDeliveries }; }; const getPublicitiesForDate = (date: Date) => { return publicities.filter(pub => { if (!pub.validFrom || !pub.validTo) return false; const pubStart = safeDate(pub.validFrom); const pubEnd = safeDate(pub.validTo); if (!pubStart || !pubEnd) return false; return date >= pubStart && date <= pubEnd; }); }; return (
{/* Calendar Header */}
{weekDays.map((day, index) => (
= 5 ? 'text-slate-700' : 'text-slate-800' } uppercase border-r border-gray-300 last:border-r-0`} > {day}
))}
{/* Calendar Days */}
{paddedDays.map((date, index) => { const isCurrentMonth = isSameMonth(date, currentDate); const isTodayDate = isToday(date); const isWeekend = date.getDay() === 0 || date.getDay() === 6; const { orders: dayOrders, deliveries: dayDeliveries } = getItemsForDate(date); const dayPublicities = getPublicitiesForDate(date); return (
onDateClick(date)} >
{/* Numéro du jour */}
{format(date, 'd')} {/* Indicateur weekend */} {isWeekend && isCurrentMonth && (
)}
{/* Orders and Deliveries - PRODUCTION OPTIMISÉ */}
{/* Publicities */} {dayPublicities.length > 0 && (
{dayPublicities.slice(0, 2).map((pub, idx) => (
pg.group?.name).join(', ')}` : ''}`} > {pub.pubNumber}
))} {dayPublicities.length > 2 && (
+{dayPublicities.length - 2}
)}
)} {/* Quick Create Button */} {isCurrentMonth && (
)}
); })}
); }