From 3b46f945a4c2b5b95598c332136f276c93fa56a7 Mon Sep 17 00:00:00 2001 From: michaelschal <35957947-michaelschal@users.noreply.replit.com> Date: Wed, 13 Aug 2025 20:34:02 +0000 Subject: [PATCH] Stabilize calendar display by refining data caching and invalidation Fix an issue where closing an order or delivery card caused all calendar entries to disappear by implementing selective cache invalidation and adjusting cache timings. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 7c468936-2a88-4686-ac0a-84921a45222d Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/7c468936-2a88-4686-ac0a-84921a45222d/B7k6m01 --- client/src/components/CalendarGrid.tsx | 36 +++++----- .../components/modals/OrderDetailModal.tsx | 39 ++++------- client/src/pages/Calendar.tsx | 65 +++++++++++-------- cookies.txt | 2 +- replit.md | 8 ++- 5 files changed, 80 insertions(+), 70 deletions(-) diff --git a/client/src/components/CalendarGrid.tsx b/client/src/components/CalendarGrid.tsx index aa908bf..64ea724 100644 --- a/client/src/components/CalendarGrid.tsx +++ b/client/src/components/CalendarGrid.tsx @@ -171,14 +171,16 @@ export default function CalendarGrid({ onDateClick, onItemClick, }: CalendarGridProps) { - console.log('🗓️ CalendarGrid rendered with:', { - currentDate: currentDate?.toISOString(), - ordersCount: orders?.length || 0, - deliveriesCount: deliveries?.length || 0, - publicitiesCount: publicities?.length || 0, - selectedStoreId, - userGroupsCount: userGroups?.length || 0 - }); + if (import.meta.env.DEV) { + console.log('🗓️ CalendarGrid rendered with:', { + currentDate: currentDate?.toISOString(), + ordersCount: orders?.length || 0, + deliveriesCount: deliveries?.length || 0, + publicitiesCount: publicities?.length || 0, + selectedStoreId, + userGroupsCount: userGroups?.length || 0 + }); + } const monthStart = startOfMonth(currentDate); const monthEnd = endOfMonth(currentDate); @@ -192,12 +194,14 @@ export default function CalendarGrid({ return []; } - console.log('🔍 CalendarGrid getPublicitiesForDate:', { - date: dateStr, - totalPublicities: publicities.length, - selectedStoreId, - userGroups: userGroups?.length || 0 - }); + if (import.meta.env.DEV) { + console.log('🔍 CalendarGrid getPublicitiesForDate:', { + date: dateStr, + totalPublicities: publicities.length, + selectedStoreId, + userGroups: userGroups?.length || 0 + }); + } try { return publicities.filter(pub => { @@ -222,7 +226,7 @@ export default function CalendarGrid({ // If no store is selected and user has no assigned groups, show only publicities with participations if (!selectedStoreId && (!userGroups || userGroups.length === 0)) { const hasParticipations = pub.participations && Array.isArray(pub.participations) && pub.participations.length > 0; - if (hasParticipations) { + if (hasParticipations && import.meta.env.DEV) { console.log('📋 Publicity has participations (no store selected):', { pubNumber: pub.pubNumber, participationCount: pub.participations.length }); } return hasParticipations; @@ -232,7 +236,7 @@ export default function CalendarGrid({ if (selectedStoreId) { const matches = pub.participations && Array.isArray(pub.participations) && pub.participations.some((pg: any) => pg?.groupId === selectedStoreId); - if (matches) { + if (matches && import.meta.env.DEV) { console.log('🎯 Publicity matches selected store:', { pubNumber: pub.pubNumber, selectedStoreId }); } return matches; diff --git a/client/src/components/modals/OrderDetailModal.tsx b/client/src/components/modals/OrderDetailModal.tsx index c81f18d..dd386fe 100644 --- a/client/src/components/modals/OrderDetailModal.tsx +++ b/client/src/components/modals/OrderDetailModal.tsx @@ -43,8 +43,8 @@ export default function OrderDetailModal({ title: "Succès", description: "Commande validée avec succès", }); + // Invalidation sélective pour éviter la disparition du calendrier queryClient.invalidateQueries({ queryKey: ['/api/orders'] }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries'] }); onClose(); }, onError: (error) => { @@ -76,8 +76,8 @@ export default function OrderDetailModal({ title: "Succès", description: "Livraison validée avec succès", }); + // Invalidation sélective pour éviter la disparition du calendrier queryClient.invalidateQueries({ queryKey: ['/api/deliveries'] }); - queryClient.invalidateQueries({ queryKey: ['/api/orders'] }); onClose(); }, onError: (error) => { @@ -103,37 +103,26 @@ export default function OrderDetailModal({ const deleteMutation = useMutation({ mutationFn: async (id: number) => { const endpoint = isOrder ? `/api/orders/${id}` : `/api/deliveries/${id}`; - console.log(`🗑️ Deleting ${isOrder ? 'order' : 'delivery'}:`, id); + if (import.meta.env.DEV) { + console.log(`🗑️ Deleting ${isOrder ? 'order' : 'delivery'}:`, id); + } await apiRequest(endpoint, "DELETE"); }, onSuccess: () => { - console.log(`✅ ${isOrder ? 'Order' : 'Delivery'} deleted successfully, clearing cache...`); + if (import.meta.env.DEV) { + console.log(`✅ ${isOrder ? 'Order' : 'Delivery'} deleted successfully`); + } toast({ title: "Succès", description: `${isOrder ? 'Commande' : 'Livraison'} supprimée avec succès`, }); - // SOLUTION PRODUCTION : Cache clearing radical pour éviter incohérences storeId - console.log('🗑️ Cache cleared, forcing page reload to maintain storeId consistency...'); - - // 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'); - } - }); + // Invalidation sélective uniquement pour l'API concernée + if (isOrder) { + queryClient.invalidateQueries({ queryKey: ['/api/orders'] }); + } else { + queryClient.invalidateQueries({ queryKey: ['/api/deliveries'] }); + } onClose(); }, diff --git a/client/src/pages/Calendar.tsx b/client/src/pages/Calendar.tsx index 6413a82..3905e10 100644 --- a/client/src/pages/Calendar.tsx +++ b/client/src/pages/Calendar.tsx @@ -49,12 +49,14 @@ export default function Calendar() { } const url = `/api/orders?${params.toString()}`; - console.log('📅 Calendar fetching orders:', { - url, - selectedStoreId, - userRole: user?.role, - params: params.toString() - }); + if (import.meta.env.DEV) { + console.log('📅 Calendar fetching orders:', { + url, + selectedStoreId, + userRole: user?.role, + params: params.toString() + }); + } const response = await fetch(url, { credentials: 'include' @@ -65,7 +67,9 @@ export default function Calendar() { } const data = await response.json(); - console.log('📅 Calendar orders received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + if (import.meta.env.DEV) { + console.log('📅 Calendar orders received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + } // Protection contre les données invalides en production if (!Array.isArray(data)) { @@ -74,6 +78,8 @@ export default function Calendar() { } return data; }, + staleTime: 5 * 60 * 1000, // 5 minutes de cache pour éviter la disparition des données + gcTime: 10 * 60 * 1000, // 10 minutes en cache }); const { data: deliveries = [], isLoading: loadingDeliveries } = useQuery({ @@ -91,12 +97,14 @@ export default function Calendar() { } const url = `/api/deliveries?${params.toString()}`; - console.log('📅 Calendar fetching deliveries:', { - url, - selectedStoreId, - userRole: user?.role, - params: params.toString() - }); + if (import.meta.env.DEV) { + console.log('📅 Calendar fetching deliveries:', { + url, + selectedStoreId, + userRole: user?.role, + params: params.toString() + }); + } const response = await fetch(url, { credentials: 'include' @@ -107,7 +115,9 @@ export default function Calendar() { } const data = await response.json(); - console.log('📅 Calendar deliveries received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + if (import.meta.env.DEV) { + console.log('📅 Calendar deliveries received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + } // Protection contre les données invalides en production if (!Array.isArray(data)) { @@ -116,6 +126,8 @@ export default function Calendar() { } return data; }, + staleTime: 5 * 60 * 1000, // 5 minutes de cache pour éviter la disparition des données + gcTime: 10 * 60 * 1000, // 10 minutes en cache }); // Fetch publicities for the current year @@ -129,12 +141,14 @@ export default function Calendar() { } const url = `/api/publicities?${params.toString()}`; - console.log('📅 Calendar fetching publicities:', { - url, - selectedStoreId, - userRole: user?.role, - year: currentDate.getFullYear() - }); + if (import.meta.env.DEV) { + console.log('📅 Calendar fetching publicities:', { + url, + selectedStoreId, + userRole: user?.role, + year: currentDate.getFullYear() + }); + } const response = await fetch(url, { credentials: 'include' @@ -145,7 +159,9 @@ export default function Calendar() { } const data = await response.json(); - console.log('📅 Calendar publicities received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + if (import.meta.env.DEV) { + console.log('📅 Calendar publicities received:', Array.isArray(data) ? data.length : 'NOT_ARRAY', 'items'); + } return Array.isArray(data) ? data : []; }, }); @@ -166,12 +182,7 @@ export default function Calendar() { }; const handleItemClick = (item: any, type: 'order' | 'delivery') => { - // Rafraîchir les données avant d'ouvrir le modal pour s'assurer d'avoir les liaisons à jour - queryClient.invalidateQueries({ queryKey: ['/api/orders'] }); - queryClient.invalidateQueries({ queryKey: ['/api/orders', selectedStoreId] }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries'] }); - queryClient.invalidateQueries({ queryKey: ['/api/deliveries', selectedStoreId] }); - + // Ne pas invalider le cache à l'ouverture pour éviter la disparition des données setSelectedItem({ ...item, type }); setShowOrderDetail(true); }; diff --git a/cookies.txt b/cookies.txt index 4390e07..fb76b7b 100644 --- a/cookies.txt +++ b/cookies.txt @@ -2,4 +2,4 @@ # https://curl.se/docs/http-cookies.html # This file was generated by libcurl! Edit at your own risk. -#HttpOnly_localhost FALSE / FALSE 1755187696 connect.sid s%3AnEg7s3fD2sLyetJTCx-VYkzZFbBkPEcf.2BsOBC1UlFIC%2BpyKgdtocMX42YO%2FZLBn1cU6UeEnIYY +#HttpOnly_localhost FALSE / FALSE 1755203512 connect.sid s%3AGm18ttGO7m1DI7WtETfDd8gMojt-FqEw.%2BP3S4uZr6aX7vk2UAaEIow8kKQlZfWMzPcKLjUHAdNI diff --git a/replit.md b/replit.md index 1186295..f53d685 100644 --- a/replit.md +++ b/replit.md @@ -19,13 +19,19 @@ La plateforme fournit une gestion robuste des flux de travail de livraison avec ## Recent Changes -### 2025-08-13 - Optimisation performance production + suppression fonctionnelle +### 2025-08-13 - Optimisation performance production + correction calendrier ✅ **Résolution latence production** : - **Problème** : Console saturée par centaines de logs "API Response" causant latence - **Solution** : Logging conditionnel - seulement en développement pour requêtes normales - **Production** : Seules les erreurs API sont loggées pour debugging - **Impact** : Réduction drastique de la charge console et amélioration performances +✅ **Problème calendrier résolu** : +- **Problème** : Fermeture carte commande/livraison faisait disparaître toutes les données +- **Cause** : Invalidation aggressive du cache React Query + invalidation à l'ouverture +- **Solution** : Cache timing optimisé (5min staleTime) + invalidation sélective seulement +- **Résultat** : Calendrier stable, plus de disparition des données au jour actuel + ✅ **Fonctionnalité suppression complètement opérationnelle** : - **Cache NocoDB** : Fonction `saveInvoiceVerificationCache` ajoutée aux deux systèmes stockage - **MemStorage** : Implémentation CRUD complète pour ordres et livraisons