mirror of
https://github.com/R0m1k3/LogiFlow.git
synced 2026-10-11 17:27:31 +02:00
feat: implement dashboard page with store-specific stats, announcement modals, and DLC alerts
This commit is contained in:
1 parent
b090c8f36a
commit
475c52cede
3 files changed
+7
-94
No files matched your search
@@ -28,9 +28,7 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
const [selectedStoreId, setSelectedStoreId] = useState<number | null>(() => {
|
const [selectedStoreId, setSelectedStoreId] = useState<number | null>(() => {
|
||||||
// Restaurer le selectedStoreId depuis localStorage si disponible
|
// Restaurer le selectedStoreId depuis localStorage si disponible
|
||||||
const saved = localStorage.getItem('selectedStoreId');
|
const saved = localStorage.getItem('selectedStoreId');
|
||||||
const restoredId = saved ? parseInt(saved) : null;
|
return saved ? parseInt(saved) : null;
|
||||||
console.log('🏪 Layout - Restoring selectedStoreId from localStorage:', { saved, restoredId });
|
|
||||||
return restoredId;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [storeInitialized, setStoreInitialized] = useState(false);
|
const [storeInitialized, setStoreInitialized] = useState(false);
|
||||||
@@ -39,10 +37,8 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
// Restaurer l'état de la sidebar depuis localStorage, mais forcer collapsed sur mobile
|
// Restaurer l'état de la sidebar depuis localStorage, mais forcer collapsed sur mobile
|
||||||
try {
|
try {
|
||||||
const saved = localStorage.getItem('sidebarCollapsed');
|
const saved = localStorage.getItem('sidebarCollapsed');
|
||||||
console.log('🔧 Layout - Restoring sidebar state:', { saved, isMobile });
|
|
||||||
return isMobile ? true : (saved ? JSON.parse(saved) : false);
|
return isMobile ? true : (saved ? JSON.parse(saved) : false);
|
||||||
} catch (error) {
|
} catch {
|
||||||
console.error('Error reading sidebar state from localStorage:', error);
|
|
||||||
return isMobile ? true : false;
|
return isMobile ? true : false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -63,55 +59,21 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
if (selectedStoreId) {
|
if (selectedStoreId) {
|
||||||
const storeExists = stores.find(store => store.id === selectedStoreId);
|
const storeExists = stores.find(store => store.id === selectedStoreId);
|
||||||
if (!storeExists) {
|
if (!storeExists) {
|
||||||
console.log('🏪 Selected store not found in available stores, clearing selection:', {
|
|
||||||
selectedStoreId,
|
|
||||||
userRole: user.role,
|
|
||||||
availableStores: stores.map(s => s.id)
|
|
||||||
});
|
|
||||||
setSelectedStoreId(null);
|
setSelectedStoreId(null);
|
||||||
localStorage.removeItem('selectedStoreId');
|
localStorage.removeItem('selectedStoreId');
|
||||||
needsUpdate = true;
|
needsUpdate = true;
|
||||||
} else {
|
|
||||||
console.log('🏪 Selected store validated successfully:', {
|
|
||||||
selectedStoreId,
|
|
||||||
userRole: user.role,
|
|
||||||
storeName: storeExists.name
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT FIX: Pour les rôles directeur/manager, forcer la sélection d'un magasin spécifique
|
// IMPORTANT FIX: Pour les rôles directeur/manager, forcer la sélection d'un magasin spécifique
|
||||||
// si aucun n'est sélectionné et qu'ils n'ont accès qu'à un seul magasin
|
// si aucun n'est sélectionné et qu'ils n'ont accès qu'à un seul magasin
|
||||||
if ((user.role === 'directeur' || user.role === 'manager') && !selectedStoreId && stores.length === 1 && !needsUpdate) {
|
if ((user.role === 'directeur' || user.role === 'manager') && !selectedStoreId && stores.length === 1 && !needsUpdate) {
|
||||||
console.log('🏪 Auto-selecting single available store for directeur/manager:', {
|
|
||||||
storeId: stores[0].id,
|
|
||||||
storeName: stores[0].name,
|
|
||||||
userRole: user.role,
|
|
||||||
userId: user.id,
|
|
||||||
previousSelectedStoreId: selectedStoreId,
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
});
|
|
||||||
const singleStoreId = stores[0].id;
|
const singleStoreId = stores[0].id;
|
||||||
setSelectedStoreId(singleStoreId);
|
setSelectedStoreId(singleStoreId);
|
||||||
localStorage.setItem('selectedStoreId', singleStoreId.toString());
|
localStorage.setItem('selectedStoreId', singleStoreId.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// VALIDATION CRITIQUE: Pour les directeurs/managers, s'assurer qu'un magasin est toujours sélectionné
|
// VALIDATION CRITIQUE: Pour les directeurs/managers, s'assurer qu'un magasin est toujours sélectionné
|
||||||
if ((user.role === 'directeur' || user.role === 'manager') && !selectedStoreId && !needsUpdate) {
|
|
||||||
console.log('🚨 CRITICAL: Directeur/Manager has no store selected, this will cause empty data display:', {
|
|
||||||
userId: user.id,
|
|
||||||
userRole: user.role,
|
|
||||||
availableStores: stores.map(s => ({ id: s.id, name: s.name }))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('🏪 Store initialization complete:', {
|
|
||||||
user: user.role,
|
|
||||||
selectedStoreId,
|
|
||||||
storesCount: stores.length,
|
|
||||||
validatedStore: selectedStoreId ? stores.find(s => s.id === selectedStoreId)?.name : 'None',
|
|
||||||
autoSelected: (user.role === 'directeur' || user.role === 'manager') && !selectedStoreId && stores.length === 1
|
|
||||||
});
|
|
||||||
setStoreInitialized(true);
|
setStoreInitialized(true);
|
||||||
}
|
}
|
||||||
}, [user, stores, selectedStoreId]);
|
}, [user, stores, selectedStoreId]);
|
||||||
@@ -172,15 +134,7 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
<Select
|
<Select
|
||||||
value={selectedStoreId?.toString() || (user.role === 'admin' ? "all" : "")}
|
value={selectedStoreId?.toString() || (user.role === 'admin' ? "all" : "")}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
console.log('🏪 Store selector changed:', {
|
|
||||||
value,
|
|
||||||
userRole: user.role,
|
|
||||||
parsed: value === "all" ? null : parseInt(value)
|
|
||||||
});
|
|
||||||
const newStoreId = value === "all" ? null : parseInt(value);
|
const newStoreId = value === "all" ? null : parseInt(value);
|
||||||
|
|
||||||
// Invalider toutes les variantes de queryKey pour changement magasin
|
|
||||||
console.log('🧹 Invalidating data caches for store change');
|
|
||||||
queryClient.invalidateQueries({
|
queryClient.invalidateQueries({
|
||||||
predicate: (query) => {
|
predicate: (query) => {
|
||||||
const key = query.queryKey;
|
const key = query.queryKey;
|
||||||
@@ -194,10 +148,8 @@ export default function Layout({ children }: LayoutProps) {
|
|||||||
// Sauvegarder dans localStorage et mettre à jour l'état
|
// Sauvegarder dans localStorage et mettre à jour l'état
|
||||||
if (newStoreId) {
|
if (newStoreId) {
|
||||||
localStorage.setItem('selectedStoreId', newStoreId.toString());
|
localStorage.setItem('selectedStoreId', newStoreId.toString());
|
||||||
console.log('💾 Store saved to localStorage:', newStoreId);
|
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('selectedStoreId');
|
localStorage.removeItem('selectedStoreId');
|
||||||
console.log('🗑️ Store removed from localStorage');
|
|
||||||
}
|
}
|
||||||
setSelectedStoreId(newStoreId);
|
setSelectedStoreId(newStoreId);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -184,11 +184,6 @@ export default function Sidebar() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Debug logging pour production
|
|
||||||
console.log('Sidebar - User:', user);
|
|
||||||
console.log('Sidebar - isLoading:', isLoading);
|
|
||||||
console.log('Sidebar - error:', error);
|
|
||||||
|
|
||||||
const handleLogout = async () => {
|
const handleLogout = async () => {
|
||||||
try {
|
try {
|
||||||
// Force logout via fetch to ensure session is destroyed
|
// Force logout via fetch to ensure session is destroyed
|
||||||
@@ -206,13 +201,11 @@ export default function Sidebar() {
|
|||||||
|
|
||||||
const toggleSidebar = () => {
|
const toggleSidebar = () => {
|
||||||
const newCollapsed = !sidebarCollapsed;
|
const newCollapsed = !sidebarCollapsed;
|
||||||
console.log('🔧 Sidebar - Toggling sidebar:', { from: sidebarCollapsed, to: newCollapsed });
|
|
||||||
setSidebarCollapsed(newCollapsed);
|
setSidebarCollapsed(newCollapsed);
|
||||||
try {
|
try {
|
||||||
localStorage.setItem('sidebarCollapsed', JSON.stringify(newCollapsed));
|
localStorage.setItem('sidebarCollapsed', JSON.stringify(newCollapsed));
|
||||||
console.log('💾 Sidebar state saved to localStorage:', newCollapsed);
|
} catch {
|
||||||
} catch (error) {
|
// ignore
|
||||||
console.error('Error saving sidebar state:', error);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -363,12 +356,7 @@ export default function Sidebar() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
const hasPermission = (roles: string[]) => {
|
const hasPermission = (roles: string[]) => {
|
||||||
const hasRole = user?.role && roles.includes(user.role);
|
return user?.role && roles.includes(user.role);
|
||||||
// Debug uniquement en développement pour éviter spam console
|
|
||||||
if (import.meta.env.MODE === 'development') {
|
|
||||||
console.log('hasPermission check:', { userRole: user?.role, roles, hasRole });
|
|
||||||
}
|
|
||||||
return hasRole;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -391,14 +379,6 @@ export default function Sidebar() {
|
|||||||
|
|
||||||
const sidebarClasses = getSidebarClasses();
|
const sidebarClasses = getSidebarClasses();
|
||||||
|
|
||||||
// Debug log pour vérifier l'état de la sidebar
|
|
||||||
console.log('🔧 Sidebar Debug:', {
|
|
||||||
isMobile,
|
|
||||||
sidebarCollapsed,
|
|
||||||
mobileMenuOpen,
|
|
||||||
width: sidebarCollapsed ? 'collapsed (64px)' : 'expanded (256px)',
|
|
||||||
classes: sidebarClasses
|
|
||||||
});
|
|
||||||
|
|
||||||
// Si l'utilisateur n'est pas encore chargé, afficher un état de chargement
|
// Si l'utilisateur n'est pas encore chargé, afficher un état de chargement
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
|
|||||||
@@ -308,15 +308,9 @@ export default function Dashboard() {
|
|||||||
}) : []; // Afficher toutes les commandes en attente
|
}) : []; // Afficher toutes les commandes en attente
|
||||||
|
|
||||||
const upcomingDeliveries = Array.isArray(allDeliveries) ? allDeliveries
|
const upcomingDeliveries = Array.isArray(allDeliveries) ? allDeliveries
|
||||||
.filter((d: any) => {
|
.filter((d: any) => d.status === 'planned')
|
||||||
const isPlanned = d.status === 'planned';
|
|
||||||
console.log('🚚 Dashboard - Delivery filter:', { id: d.id, status: d.status, isPlanned, scheduledDate: d.scheduledDate });
|
|
||||||
return isPlanned;
|
|
||||||
})
|
|
||||||
.sort((a: any, b: any) => new Date(a.scheduledDate).getTime() - new Date(b.scheduledDate).getTime())
|
.sort((a: any, b: any) => new Date(a.scheduledDate).getTime() - new Date(b.scheduledDate).getTime())
|
||||||
.slice(0, 4) : []; // Afficher les 4 prochaines livraisons
|
.slice(0, 4) : [];
|
||||||
|
|
||||||
console.log('🚚 Dashboard - Upcoming deliveries result:', upcomingDeliveries.length, upcomingDeliveries);
|
|
||||||
|
|
||||||
// Calculs pour les statistiques
|
// Calculs pour les statistiques
|
||||||
const pendingOrdersCount = Array.isArray(allOrders) ? allOrders.filter((order: any) => order.status === 'pending').length : 0;
|
const pendingOrdersCount = Array.isArray(allOrders) ? allOrders.filter((order: any) => order.status === 'pending').length : 0;
|
||||||
@@ -373,19 +367,6 @@ export default function Dashboard() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('📊 Dashboard Debug - Raw Data:', {
|
|
||||||
allOrders: Array.isArray(allOrders) ? allOrders.length : 'NOT_ARRAY',
|
|
||||||
allDeliveries: Array.isArray(allDeliveries) ? allDeliveries.length : 'NOT_ARRAY',
|
|
||||||
customerOrders: Array.isArray(customerOrders) ? customerOrders.length : 'NOT_ARRAY',
|
|
||||||
upcomingPublicities: Array.isArray(upcomingPublicities) ? upcomingPublicities.length : 'NOT_ARRAY',
|
|
||||||
stats: stats,
|
|
||||||
samples: {
|
|
||||||
order: Array.isArray(allOrders) && allOrders.length > 0 ? allOrders[0] : null,
|
|
||||||
delivery: Array.isArray(allDeliveries) && allDeliveries.length > 0 ? allDeliveries[0] : null,
|
|
||||||
customerOrder: Array.isArray(customerOrders) && customerOrders.length > 0 ? customerOrders[0] : null,
|
|
||||||
publicity: Array.isArray(upcomingPublicities) && upcomingPublicities.length > 0 ? upcomingPublicities[0] : null
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Statistiques pour les commandes clients
|
// Statistiques pour les commandes clients
|
||||||
const ordersByStatus = {
|
const ordersByStatus = {
|
||||||
|
|||||||
Reference in new issue
Block a user