From 7a534e4fc341b56a4f79b6df18befe0b49703ade Mon Sep 17 00:00:00 2001
From: michaelschal <35957947-michaelschal@users.noreply.replit.com>
Date: Mon, 11 Aug 2025 21:37:47 +0000
Subject: [PATCH] Enhance calendar view with detailed order and delivery item
display
Add a new `CalendarItem` component to visually represent orders and deliveries in the calendar grid, including status indicators and click handlers. Implement a `DayItemsContainer` to manage and display multiple items per day, with overflow handling via a popover.
Replit-Commit-Author: Agent
Replit-Commit-Session-Id: b163d4c0-de5e-4f4e-a9c0-aed4c7049718
Replit-Commit-Checkpoint-Type: full_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/b163d4c0-de5e-4f4e-a9c0-aed4c7049718/2ecSf3X
---
client/src/components/CalendarGrid.tsx | 223 +++++++++++++++++--------
1 file changed, 152 insertions(+), 71 deletions(-)
diff --git a/client/src/components/CalendarGrid.tsx b/client/src/components/CalendarGrid.tsx
index 7eb7caf..fa86377 100644
--- a/client/src/components/CalendarGrid.tsx
+++ b/client/src/components/CalendarGrid.tsx
@@ -1,8 +1,10 @@
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 } from "lucide-react";
+import { Plus, Check, MoreHorizontal } from "lucide-react";
import { Button } from "@/components/ui/button";
+import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
+import { useState } from "react";
import type { OrderWithRelations, DeliveryWithRelations } from "@shared/schema";
interface CalendarGridProps {
@@ -13,6 +15,149 @@ interface CalendarGridProps {
onItemClick: (item: any, type: 'order' | 'delivery') => void;
}
+// Composant pour afficher un élément (commande ou livraison)
+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 colorClass = item.status === 'delivered'
+ ? 'bg-delivered text-white'
+ : item.status === 'planned'
+ ? 'bg-orange-500 text-white border-2 border-orange-300'
+ : 'bg-primary text-white';
+
+ return (
+
{
+ e.stopPropagation();
+ onItemClick(item, 'order');
+ }}
+ >
+
+ {item.supplier.name}
+
+
+ {item.status === 'planned' && (
+
+ )}
+ {item.status === 'delivered' && (
+
+ )}
+
+
+ );
+ }
+
+ // Livraison
+ return (
+ {
+ e.stopPropagation();
+ onItemClick(item, 'delivery');
+ }}
+ >
+
+ {item.supplier.name} - {formatQuantity(item.quantity, item.unit)}
+
+
+ {item.status === 'pending' && (
+
+ )}
+ {item.status === 'delivered' && (
+
+ )}
+
+
+ );
+}
+
+// Composant pour gérer l'overflow avec popover
+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 = 2;
+ 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 popover */}
+ {hiddenCount > 0 && (
+
+
+
+
+ e.stopPropagation()}
+ >
+
+
+ Tous les éléments ({totalItems})
+
+
+ {allItems.map((item) => (
+ {
+ onItemClick(clickedItem, type);
+ setIsOpen(false);
+ }}
+ />
+ ))}
+
+
+
+
+ )}
+
+ );
+}
+
export default function CalendarGrid({
currentDate,
orders,
@@ -118,10 +263,6 @@ export default function CalendarGrid({
return { orders: dayOrders, deliveries: dayDeliveries };
};
- const formatQuantity = (quantity: number, unit: string) => {
- return `${quantity}${unit === 'palettes' ? 'P' : 'C'}`;
- };
-
return (
{/* Calendar Header */}
@@ -161,72 +302,12 @@ export default function CalendarGrid({
{format(date, 'd')}
- {/* Orders and Deliveries */}
-
- {dayOrders.map((order) => {
- // Vérifier si la commande a une livraison liée (peu importe le statut)
- const hasLinkedDelivery = order.deliveries && order.deliveries.length > 0;
-
- const colorClass = order.status === 'delivered'
- ? 'bg-delivered text-white'
- : order.status === 'planned'
- ? 'bg-orange-500 text-white border-2 border-orange-300'
- : 'bg-primary text-white';
-
- return (
-
{
- e.stopPropagation();
- onItemClick(order, 'order');
- }}
- >
-
- {order.supplier.name}
-
-
-
- {order.status === 'planned' && (
-
- )}
- {order.status === 'delivered' && (
-
- )}
-
-
- );
- })}
-
- {dayDeliveries.map((delivery) => (
-
{
- e.stopPropagation();
- onItemClick(delivery, 'delivery');
- }}
- >
-
- {delivery.supplier.name} - {formatQuantity(delivery.quantity, delivery.unit)}
-
-
- {delivery.status === 'pending' && (
-
- )}
- {delivery.status === 'delivered' && (
-
- )}
-
-
- ))}
-
+ {/* Orders and Deliveries avec système d'overflow */}
+
{/* Quick Create Button */}