diff --git a/client/src/components/CalendarGrid.tsx b/client/src/components/CalendarGrid.tsx index 5c9e21b..aa908bf 100644 --- a/client/src/components/CalendarGrid.tsx +++ b/client/src/components/CalendarGrid.tsx @@ -171,6 +171,14 @@ 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 + }); const monthStart = startOfMonth(currentDate); const monthEnd = endOfMonth(currentDate); @@ -178,29 +186,42 @@ export default function CalendarGrid({ const getPublicitiesForDate = (date: Date) => { const dateStr = format(date, 'yyyy-MM-dd'); + // Protection contre les données invalides qui causent des plantages en production + if (!publicities || !Array.isArray(publicities)) { + console.warn('⚠️ Invalid publicities data:', publicities); + return []; + } + console.log('🔍 CalendarGrid getPublicitiesForDate:', { date: dateStr, totalPublicities: publicities.length, selectedStoreId, - userGroups: userGroups.length + userGroups: userGroups?.length || 0 }); - if (publicities.length > 0) { - console.log('📄 Sample publicity structure:', publicities[0]); - } - - return publicities.filter(pub => { + try { + return publicities.filter(pub => { + // Vérifications de sécurité pour éviter les plantages + if (!pub || typeof pub !== 'object') { + console.warn('⚠️ Invalid publicity object:', pub); + return false; + } // Check if the date is within the publicity period const pubStart = pub.startDate; const pubEnd = pub.endDate; + if (!pubStart || !pubEnd) { + console.warn('⚠️ Publicity missing dates:', { pubNumber: pub.pubNumber, startDate: pubStart, endDate: pubEnd }); + return false; + } + if (dateStr < pubStart || dateStr > pubEnd) { return false; } // 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 && pub.participations.length > 0; + const hasParticipations = pub.participations && Array.isArray(pub.participations) && pub.participations.length > 0; if (hasParticipations) { console.log('📋 Publicity has participations (no store selected):', { pubNumber: pub.pubNumber, participationCount: pub.participations.length }); } @@ -209,7 +230,8 @@ export default function CalendarGrid({ // If a specific store is selected, check if that store participates if (selectedStoreId) { - const matches = pub.participations?.some((pg: any) => pg.groupId === selectedStoreId); + const matches = pub.participations && Array.isArray(pub.participations) && + pub.participations.some((pg: any) => pg?.groupId === selectedStoreId); if (matches) { console.log('🎯 Publicity matches selected store:', { pubNumber: pub.pubNumber, selectedStoreId }); } @@ -218,9 +240,10 @@ export default function CalendarGrid({ // If no specific store selected but user has assigned stores, // show publicities where any of user's stores participate - if (userGroups && userGroups.length > 0) { - const userGroupIds = userGroups.map((ug: any) => ug.groupId); - const matches = pub.participations?.some((pg: any) => userGroupIds.includes(pg.groupId)); + if (userGroups && Array.isArray(userGroups) && userGroups.length > 0) { + const userGroupIds = userGroups.map((ug: any) => ug?.groupId).filter(id => id !== undefined); + const matches = pub.participations && Array.isArray(pub.participations) && + pub.participations.some((pg: any) => pg?.groupId && userGroupIds.includes(pg.groupId)); if (matches) { console.log('👥 Publicity matches user groups:', { pubNumber: pub.pubNumber, userGroupIds }); } @@ -228,12 +251,16 @@ export default function CalendarGrid({ } // Default case: only show publicities with participations - const hasParticipations = pub.participations && pub.participations.length > 0; + const hasParticipations = pub.participations && Array.isArray(pub.participations) && pub.participations.length > 0; if (hasParticipations) { console.log('📋 Publicity has participations (default case):', { pubNumber: pub.pubNumber, participationCount: pub.participations.length }); } return hasParticipations; - }); + }); + } catch (error) { + console.error('❌ Error filtering publicities:', error); + return []; + } }; // Get all days in the month diff --git a/client/src/pages/Calendar.tsx b/client/src/pages/Calendar.tsx index a8fdc8d..b94b329 100644 --- a/client/src/pages/Calendar.tsx +++ b/client/src/pages/Calendar.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; import { useQuery, useQueryClient } from "@tanstack/react-query"; -import { ChevronLeft, ChevronRight, Plus, RefreshCw } from "lucide-react"; +import { ChevronLeft, ChevronRight, Plus, RefreshCw, Calendar as CalendarIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; import CalendarGrid from "@/components/CalendarGrid"; import QuickCreateMenu from "@/components/modals/QuickCreateMenu"; @@ -65,6 +65,12 @@ export default function Calendar() { const data = await response.json(); 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)) { + console.warn('⚠️ Orders data is not an array, returning empty array'); + return []; + } return data; }, }); @@ -101,6 +107,12 @@ export default function Calendar() { const data = await response.json(); 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)) { + console.warn('⚠️ Deliveries data is not an array, returning empty array'); + return []; + } return data; }, }); @@ -183,7 +195,7 @@ export default function Calendar() {
- +

Calendrier des Commandes & Livraisons @@ -259,9 +271,9 @@ export default function Calendar() { ) : ( { res.json(group); } catch (error) { console.error('❌ Failed to create group:', { - error: error.message, + error: (error as Error).message, stack: error.stack, body: req.body, userId: req.user?.id || req.user?.claims?.sub || 'unknown' @@ -256,7 +256,7 @@ export async function registerRoutes(app: Express): Promise { res.json(supplier); } catch (error) { console.error('❌ Failed to create supplier:', { - error: error.message, + error: (error as Error).message, stack: error.stack, body: req.body, userId: req.user?.id || req.user?.claims?.sub || 'unknown' @@ -438,7 +438,7 @@ export async function registerRoutes(app: Express): Promise { res.json(order); } catch (error) { console.error("❌ Error creating order:", { - error: error.message, + error: (error as Error).message, stack: error.stack, body: req.body, userId: req.user?.id || req.user?.claims?.sub || 'unknown' @@ -576,7 +576,7 @@ export async function registerRoutes(app: Express): Promise { } catch (error) { console.error("❌ Error in sync operation:", error); - res.status(500).json({ message: "Failed to synchronize statuses", error: error.message }); + res.status(500).json({ message: "Failed to synchronize statuses", error: (error as Error).message }); } }); @@ -981,7 +981,7 @@ export async function registerRoutes(app: Express): Promise { res.json(usersWithData); } catch (error) { console.error("❌ Critical error fetching users:", error); - console.error("❌ Error stack:", error.stack); + console.error("❌ Error stack:", (error as any).stack); // En cas d'erreur, retourner un array vide pour éviter React Error #310 res.status(500).json([]); } @@ -1048,10 +1048,10 @@ export async function registerRoutes(app: Express): Promise { res.json(newUser); } catch (error) { console.error("❌ Error creating user:", error); - console.error("❌ Error type:", error.constructor.name); - console.error("❌ Error code:", error.code); - console.error("❌ Error constraint:", error.constraint); - console.error("❌ Error stack:", error.stack); + console.error("❌ Error type:", (error as any).constructor?.name); + console.error("❌ Error code:", (error as any).code); + console.error("❌ Error constraint:", (error as any).constraint); + console.error("❌ Error stack:", (error as any).stack); if (error instanceof z.ZodError) { console.log('❌ Validation error:', error.errors); @@ -1059,13 +1059,13 @@ export async function registerRoutes(app: Express): Promise { } // Handle specific database constraint errors - if (error.code === '23505') { - if (error.constraint === 'users_username_key') { + if ((error as any).code === '23505') { + if ((error as any).constraint === 'users_username_key') { return res.status(409).json({ message: "Un utilisateur avec ce nom d'utilisateur existe déjà. Veuillez choisir un autre nom d'utilisateur." }); } - if (error.constraint === 'users_email_key') { + if ((error as any).constraint === 'users_email_key') { return res.status(409).json({ message: "Un utilisateur avec cette adresse email existe déjà." }); @@ -1073,7 +1073,7 @@ export async function registerRoutes(app: Express): Promise { } // Handle connection errors - if (error.code === 'ECONNREFUSED' || error.code === 'ENOTFOUND') { + if ((error as any).code === 'ECONNREFUSED' || (error as any).code === 'ENOTFOUND') { return res.status(503).json({ message: "Database connection error" }); } @@ -1135,23 +1135,23 @@ export async function registerRoutes(app: Express): Promise { res.json(updatedUser); } catch (error: any) { console.error("❌ Error updating user:", error); - console.error("❌ Error type:", error.constructor.name); - console.error("❌ Error code:", error.code); - console.error("❌ Error constraint:", error.constraint); - console.error("❌ Error stack:", error.stack); + console.error("❌ Error type:", (error as any).constructor?.name); + console.error("❌ Error code:", (error as any).code); + console.error("❌ Error constraint:", (error as any).constraint); + console.error("❌ Error stack:", (error as any).stack); if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid user data", errors: error.errors }); } // Handle specific database constraint errors - if (error.code === '23505') { - if (error.constraint === 'users_username_key') { + if ((error as any).code === '23505') { + if ((error as any).constraint === 'users_username_key') { return res.status(409).json({ message: "Un utilisateur avec ce nom d'utilisateur existe déjà. Veuillez choisir un autre nom d'utilisateur." }); } - if (error.constraint === 'users_email_key') { + if ((error as any).constraint === 'users_email_key') { return res.status(409).json({ message: "Un utilisateur avec cette adresse email existe déjà. Veuillez utiliser une autre adresse email ou laisser le champ vide." }); @@ -1254,7 +1254,7 @@ export async function registerRoutes(app: Express): Promise { res.json(publicities); } catch (error) { console.error("Error fetching publicities:", error); - res.status(500).json({ message: "Failed to fetch publicities" }); + res.status(500).json({ message: "Failed to fetch publicities", error: (error as Error).message }); } }); @@ -1275,7 +1275,7 @@ export async function registerRoutes(app: Express): Promise { // Check access permissions if (user.role !== 'admin') { const userGroupIds = user.userGroups.map(ug => ug.groupId); - const hasAccess = publicity.participations.some(p => userGroupIds.includes(p.groupId)); + const hasAccess = publicity.participations.some((p: any) => userGroupIds.includes(p.groupId)); if (!hasAccess) { return res.status(403).json({ message: "Access denied" }); @@ -2286,7 +2286,7 @@ export async function registerRoutes(app: Express): Promise { res.json(updatedTask); } catch (error) { console.error("❌ Error completing task:", error); - res.status(500).json({ message: "Failed to complete task", error: error.message }); + res.status(500).json({ message: "Failed to complete task", error: (error as Error).message }); } }); @@ -2343,44 +2343,31 @@ export async function registerRoutes(app: Express): Promise { timestamp: new Date().toISOString() }); } catch (error) { - res.status(500).json({ error: error.message }); + res.status(500).json({ error: (error as Error).message }); } }); // Debug endpoint to check task permissions specifically - // Test CRITIQUE - Comparaison des storages pour permissions tâches - app.get('/api/debug/compare-storages', isAuthenticated, async (req: any, res) => { + // Debug endpoint for permissions status + app.get('/api/debug/permissions-status', isAuthenticated, async (req: any, res) => { try { - console.log('🔍 CRITICAL TEST - Comparing dev vs prod storage for task permissions'); - - // Test développement - const devTaskPerms = devPermissions.filter(p => p.category === 'gestion_taches'); - console.log('📋 DEV storage - Task permissions:', devTaskPerms.length); - - // Test production - const prodTaskPerms = prodPermissions.filter(p => p.category === 'gestion_taches'); - console.log('📋 PROD storage - Task permissions:', prodTaskPerms.length); + const userId = req.user.claims ? req.user.claims.sub : req.user.id; + const user = await storage.getUserWithGroups(userId); res.json({ - development: { - total: devPermissions.length, - task_permissions: devTaskPerms.length, - categories: [...new Set(devPermissions.map(p => p.category))].sort(), - task_details: devTaskPerms - }, - production: { - total: prodPermissions.length, - task_permissions: prodTaskPerms.length, - categories: [...new Set(prodPermissions.map(p => p.category))].sort(), - task_details: prodTaskPerms - }, - database_verified: true, + user: user ? { + id: user.id, + username: user.username, + role: user.role, + groupCount: user.userGroups.length + } : null, + permissionSystemType: 'hardcoded', timestamp: new Date().toISOString() }); } catch (error) { - console.error('❌ Storage comparison error:', error); - res.status(500).json({ error: error.message }); + console.error('❌ Permissions status error:', error); + res.status(500).json({ error: (error as Error).message }); } });