Files
projet_gestion_commande/mobile/src/context/CartContext.tsx
T
2026-03-02 03:28:45 +01:00

223 lines
6.5 KiB
TypeScript

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<CartItem, "id">) => Promise<void>;
removeFromCart: (id: number) => Promise<void>;
clearCart: () => Promise<void>;
cartCount: number;
cartTotal: number;
loading: boolean;
refreshCart: () => Promise<void>;
toast: ToastData | null;
clearToast: () => void;
isAuthenticated: boolean;
}
const CartContext = createContext<CartContextType | undefined>(undefined);
export function CartProvider({ children }: { children: ReactNode }) {
const [cartItems, setCartItems] = useState<CartItem[]>([]);
const [loading, setLoading] = useState(false);
const [toast, setToast] = useState<ToastData | null>(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<string | null> => {
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<CartItem, "id">) => {
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 (
<CartContext.Provider
value={{
cartItems,
addToCart,
removeFromCart,
clearCart: clearCartAction,
cartCount,
cartTotal,
loading,
refreshCart,
toast,
clearToast,
isAuthenticated,
}}
>
{children}
</CartContext.Provider>
);
}
export function useCart() {
const context = useContext(CartContext);
if (!context) throw new Error("useCart must be used within a CartProvider");
return context;
}