import { useState, useEffect } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { AlertTriangle, XCircle, Clock, PackageX, Eye, ArrowRight } from "lucide-react"; import { useToast } from "@/hooks/use-toast"; import { apiRequest } from "@/lib/queryClient"; interface DlcProduct { id: number; productName: string; expiryDate: string; supplier: { name: string }; status: string; stockEpuise: boolean; } interface DlcAlertModalProps { isOpen: boolean; onClose: () => void; dlcStats: { expired: number; expiringSoon: number; active: number }; selectedStoreId?: number; } export function DlcAlertModal({ isOpen, onClose, dlcStats, selectedStoreId }: DlcAlertModalProps) { const { toast } = useToast(); const queryClient = useQueryClient(); const [snoozeUntil, setSnoozeUntil] = useState(null); // Invalider les queries DLC quand le magasin change useEffect(() => { queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] }); }, [selectedStoreId, queryClient]); // Fetch detailed DLC products for the modal const { data: expiredProducts = [] } = useQuery({ queryKey: ["/api/dlc-products", "expires", selectedStoreId], queryFn: () => { const params = new URLSearchParams(); params.append("status", "expires"); if (selectedStoreId) params.append("storeId", selectedStoreId.toString()); return fetch(`/api/dlc-products?${params}`, { credentials: 'include' }) .then(res => res.json()); }, enabled: isOpen && dlcStats.expired > 0, }); const { data: expiringSoonProducts = [] } = useQuery({ queryKey: ["/api/dlc-products", "expires_soon", selectedStoreId], queryFn: () => { const params = new URLSearchParams(); params.append("status", "expires_soon"); if (selectedStoreId) params.append("storeId", selectedStoreId.toString()); return fetch(`/api/dlc-products?${params}`, { credentials: 'include' }) .then(res => res.json()); }, enabled: isOpen && dlcStats.expiringSoon > 0, }); // Mutation to mark product as stock depleted const markStockEpuiseMutation = useMutation({ mutationFn: (productId: number) => apiRequest(`/api/dlc-products/${productId}/stock-epuise`, "PUT"), onSuccess: () => { toast({ title: "✅ Produit marqué", description: "Le produit a été marqué comme stock épuisé", }); // Refresh DLC stats and products queryClient.invalidateQueries({ queryKey: ["/api/dlc-products"] }); }, onError: () => { toast({ title: "❌ Erreur", description: "Impossible de marquer le produit comme épuisé", variant: "destructive", }); }, }); // Calculate days until expiry const getDaysUntilExpiry = (expiryDate: string) => { const today = new Date(); const expiry = new Date(expiryDate); const diffTime = expiry.getTime() - today.getTime(); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)); return diffDays; }; // Handle temporary snooze (2 hours) const handleSnooze = () => { const snoozeTime = new Date(); snoozeTime.setHours(snoozeTime.getHours() + 2); setSnoozeUntil(snoozeTime); localStorage.setItem('dlcAlertSnooze', snoozeTime.toISOString()); onClose(); }; // Check if modal should be snoozed useEffect(() => { const snoozedUntil = localStorage.getItem('dlcAlertSnooze'); if (snoozedUntil) { const snoozeDate = new Date(snoozedUntil); if (new Date() < snoozeDate) { setSnoozeUntil(snoozeDate); } else { localStorage.removeItem('dlcAlertSnooze'); } } }, []); // Don't show if snoozed if (snoozeUntil && new Date() < snoozeUntil) { return null; } // Don't show if no issues if (dlcStats.expired === 0 && dlcStats.expiringSoon === 0) { return null; } const handleMarkStockEpuise = (productId: number) => { markStockEpuiseMutation.mutate(productId); }; const handleViewDlcModule = () => { window.location.href = '/dlc'; }; return ( Alerte Produits DLC - Action Requise Des produits nécessitent votre attention immédiate pour éviter le gaspillage et respecter la sécurité alimentaire.
{/* Expired Products */} {dlcStats.expired > 0 && (

Produits Expirés ({dlcStats.expired})

{expiredProducts.slice(0, 8).map((product) => (
{product.productName}
{product.supplier.name} • Expiré depuis {Math.abs(getDaysUntilExpiry(product.expiryDate))} jour(s)
{!product.stockEpuise && ( )} {product.stockEpuise && ( Stock épuisé )}
))} {expiredProducts.length > 8 && (
et {expiredProducts.length - 8} autre(s) produit(s) expiré(s)...
)}
)} {/* Expiring Soon Products */} {dlcStats.expiringSoon > 0 && (

Expirent Bientôt ({dlcStats.expiringSoon})

{expiringSoonProducts.slice(0, 8).map((product) => { const daysLeft = getDaysUntilExpiry(product.expiryDate); return (
{product.productName}
{product.supplier.name} • Expire dans {daysLeft} jour(s)
{daysLeft <= 3 ? 'URGENT' : `${daysLeft}j`}
); })} {expiringSoonProducts.length > 8 && (
et {expiringSoonProducts.length - 8} autre(s) produit(s) expirant bientôt...
)}
)}
{/* Action Buttons */}
{/* Help Text */}
💡 Conseil : Ce modal réapparaîtra tant que les produits ne sont pas traités. Marquez les produits comme "stock épuisé" ou traitez-les dans le module DLC pour faire disparaître l'alerte.
); }