import React, { createContext, useContext, useState, useEffect, useCallback, type ReactNode, } from "react"; import { getCart, addToCart as apiAddToCart, removeFromCart as apiRemoveFromCart, clearCart as apiClearCart, } from "../api/api"; import { getToken } from "../auth/tokenStorage"; import { extractUsernameFromToken } from "../auth/jwtUtils"; export interface CartItem { id: number; product_id: number; name_product: string; price: number; quantity: number; category: string; image?: string; } interface ToastData { message: string; type: "success" | "error" | "warning" | "info"; } interface CartContextType { cartItems: CartItem[]; addToCart: (item: Omit) => Promise; removeFromCart: (id: number) => Promise; clearCart: () => Promise; cartCount: number; cartTotal: number; loading: boolean; refreshCart: () => Promise; toast: ToastData | null; clearToast: () => void; isAuthenticated: boolean; } const CartContext = createContext(undefined); export function CartProvider({ children }: { children: ReactNode }) { const [cartItems, setCartItems] = useState([]); const [loading, setLoading] = useState(false); const [toast, setToast] = useState(null); const [isAuthenticated, setIsAuthenticated] = useState(false); const showToast = ( message: string, type: ToastData["type"] = "success", ) => { setToast({ message, type }); setTimeout(() => setToast(null), 3000); }; const clearToast = () => setToast(null); const getUsername = async (): Promise => { const token = await getToken(); if (!token) return null; return extractUsernameFromToken(token); }; const refreshCart = useCallback(async () => { const username = await getUsername(); if (!username) { setCartItems([]); setIsAuthenticated(false); return; } setIsAuthenticated(true); setLoading(true); try { const response = await getCart(username); if (response.success && response.panier) { const items: CartItem[] = response.panier.map((item: any) => ({ id: item.id, product_id: item.product_id, name_product: item.product_name || item.name_product || "Produit", price: item.price, quantity: item.quantity, category: (item.category || "autre").toLowerCase().trim(), image: item.image, })); setCartItems(items); } else { setCartItems([]); } } catch { setCartItems([]); } finally { setLoading(false); } }, []); useEffect(() => { refreshCart(); }, [refreshCart]); const addToCart = async (item: Omit) => { const username = await getUsername(); if (!username) { showToast("Vous devez être connecté.", "warning"); return; } if (!item.quantity || item.quantity <= 0) { showToast("Quantité invalide", "error"); return; } const cleanName = (item.name_product || "Produit") .replace(/\s*\([^)]*\)\s*/g, "") .trim(); setLoading(true); try { const response = await apiAddToCart({ username, product_id: item.product_id, name_product: cleanName, category: (item.category || "autre").toLowerCase().trim(), quantity: Number(item.quantity), price: Number(item.price) || 0, }); if (response.success) { await refreshCart(); showToast( `${cleanName} (${item.quantity}g) ajouté !`, "success", ); } else { showToast( response.message || "Erreur lors de l'ajout", "error", ); } } catch { showToast("Erreur lors de l'ajout", "error"); } finally { setLoading(false); } }; const removeFromCart = async (id: number) => { const username = await getUsername(); if (!username) { showToast("Vous devez être connecté.", "warning"); return; } setLoading(true); try { const response = await apiRemoveFromCart(id, username); if (response.success) { await refreshCart(); showToast("Produit supprimé", "success"); } else { showToast(response.message || "Erreur suppression", "error"); } } catch { showToast("Erreur suppression", "error"); } finally { setLoading(false); } }; const clearCartAction = async () => { const username = await getUsername(); if (!username) { showToast("Vous devez être connecté.", "warning"); return; } setLoading(true); try { const response = await apiClearCart(username); if (response.success) { setCartItems([]); showToast(response.message || "Panier vidé", "success"); } else { showToast(response.message || "Erreur vidage", "error"); } } catch { showToast("Erreur vidage", "error"); } finally { setLoading(false); } }; const cartCount = cartItems.length; const cartTotal = cartItems.reduce((sum, item) => sum + item.price, 0); return ( {children} ); } export function useCart() { const context = useContext(CartContext); if (!context) throw new Error("useCart must be used within a CartProvider"); return context; }