chore: update icon

This commit is contained in:
2026-03-01 14:38:31 +01:00
parent 96daad954e
commit 5ac024cc70
3 changed files with 193 additions and 159 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 952 KiB

After

Width:  |  Height:  |  Size: 761 KiB

+193 -155
View File
@@ -1,183 +1,221 @@
import React, { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'; import React, {
createContext,
useContext,
useState,
useEffect,
useCallback,
type ReactNode,
} from "react";
import { import {
getCart, addToCart as apiAddToCart, getCart,
removeFromCart as apiRemoveFromCart, clearCart as apiClearCart, addToCart as apiAddToCart,
} from '../api/api'; removeFromCart as apiRemoveFromCart,
import { getToken } from '../auth/tokenStorage'; clearCart as apiClearCart,
import { extractUsernameFromToken } from '../auth/jwtUtils'; } from "../api/api";
import { getToken } from "../auth/tokenStorage";
import { extractUsernameFromToken } from "../auth/jwtUtils";
export interface CartItem { export interface CartItem {
id: number; id: number;
product_id: number; product_id: number;
name_product: string; name_product: string;
price: number; price: number;
quantity: number; // grammes quantity: number;
category: string; category: string;
image?: string; image?: string;
} }
interface ToastData { interface ToastData {
message: string; message: string;
type: 'success' | 'error' | 'warning' | 'info'; type: "success" | "error" | "warning" | "info";
} }
interface CartContextType { interface CartContextType {
cartItems: CartItem[]; cartItems: CartItem[];
addToCart: (item: Omit<CartItem, 'id'>) => Promise<void>; addToCart: (item: Omit<CartItem, "id">) => Promise<void>;
removeFromCart: (id: number) => Promise<void>; removeFromCart: (id: number) => Promise<void>;
clearCart: () => Promise<void>; clearCart: () => Promise<void>;
cartCount: number; cartCount: number;
cartTotal: number; cartTotal: number;
loading: boolean; loading: boolean;
refreshCart: () => Promise<void>; refreshCart: () => Promise<void>;
toast: ToastData | null; toast: ToastData | null;
clearToast: () => void; clearToast: () => void;
isAuthenticated: boolean; isAuthenticated: boolean;
} }
const CartContext = createContext<CartContextType | undefined>(undefined); const CartContext = createContext<CartContextType | undefined>(undefined);
export function CartProvider({ children }: { children: ReactNode }) { export function CartProvider({ children }: { children: ReactNode }) {
const [cartItems, setCartItems] = useState<CartItem[]>([]); const [cartItems, setCartItems] = useState<CartItem[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [toast, setToast] = useState<ToastData | null>(null); const [toast, setToast] = useState<ToastData | null>(null);
const [isAuthenticated, setIsAuthenticated] = useState(false); const [isAuthenticated, setIsAuthenticated] = useState(false);
const showToast = (message: string, type: ToastData['type'] = 'success') => { const showToast = (
setToast({ message, type }); message: string,
setTimeout(() => setToast(null), 3000); type: ToastData["type"] = "success",
}; ) => {
setToast({ message, type });
setTimeout(() => setToast(null), 3000);
};
const clearToast = () => setToast(null); const clearToast = () => setToast(null);
const getUsername = async (): Promise<string | null> => { const getUsername = async (): Promise<string | null> => {
const token = await getToken(); const token = await getToken();
if (!token) return null; if (!token) return null;
return extractUsernameFromToken(token); return extractUsernameFromToken(token);
}; };
const refreshCart = useCallback(async () => { const refreshCart = useCallback(async () => {
const username = await getUsername(); const username = await getUsername();
if (!username) { if (!username) {
setCartItems([]); setCartItems([]);
setIsAuthenticated(false); setIsAuthenticated(false);
return; return;
} }
setIsAuthenticated(true); setIsAuthenticated(true);
setLoading(true); setLoading(true);
try { try {
const response = await getCart(username); const response = await getCart(username);
if (response.success && response.panier) { if (response.success && response.panier) {
const items: CartItem[] = response.panier.map((item: any) => ({ const items: CartItem[] = response.panier.map((item: any) => ({
id: item.id, id: item.id,
product_id: item.product_id, product_id: item.product_id,
name_product: item.product_name || item.name_product || 'Produit', name_product:
price: item.price, item.product_name || item.name_product || "Produit",
quantity: item.quantity, price: item.price,
category: (item.category || 'autre').toLowerCase().trim(), quantity: item.quantity,
image: item.image, category: (item.category || "autre").toLowerCase().trim(),
})); image: item.image,
setCartItems(items); }));
} else { setCartItems(items);
setCartItems([]); } else {
} setCartItems([]);
} catch { }
setCartItems([]); } catch {
} finally { setCartItems([]);
setLoading(false); } finally {
} setLoading(false);
}, []); }
}, []);
useEffect(() => { useEffect(() => {
refreshCart(); refreshCart();
}, [refreshCart]); }, [refreshCart]);
const addToCart = async (item: Omit<CartItem, 'id'>) => { const addToCart = async (item: Omit<CartItem, "id">) => {
const username = await getUsername(); const username = await getUsername();
if (!username) { if (!username) {
showToast('Vous devez être connecté.', 'warning'); showToast("Vous devez être connecté.", "warning");
return; return;
} }
if (!item.quantity || item.quantity <= 0) { if (!item.quantity || item.quantity <= 0) {
showToast('Quantité invalide', 'error'); showToast("Quantité invalide", "error");
return; return;
} }
const cleanName = (item.name_product || 'Produit').replace(/\s*\([^)]*\)\s*/g, '').trim(); const cleanName = (item.name_product || "Produit")
setLoading(true); .replace(/\s*\([^)]*\)\s*/g, "")
try { .trim();
const response = await apiAddToCart({ setLoading(true);
username, try {
name_product: cleanName, const response = await apiAddToCart({
category: (item.category || 'autre').toLowerCase().trim(), username,
quantity: Number(item.quantity), name_product: cleanName,
price: Number(item.price) || 0, category: (item.category || "autre").toLowerCase().trim(),
}); quantity: Number(item.quantity),
if (response.success) { price: Number(item.price) || 0,
await refreshCart(); });
showToast(`${cleanName} (${item.quantity}g) ajouté !`, 'success'); if (response.success) {
} else { await refreshCart();
showToast(response.message || "Erreur lors de l'ajout", 'error'); showToast(
} `${cleanName} (${item.quantity}g) ajouté !`,
} catch { "success",
showToast("Erreur lors de l'ajout", 'error'); );
} finally { } else {
setLoading(false); 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 removeFromCart = async (id: number) => {
const username = await getUsername(); const username = await getUsername();
if (!username) { showToast('Vous devez être connecté.', 'warning'); return; } if (!username) {
setLoading(true); showToast("Vous devez être connecté.", "warning");
try { return;
const response = await apiRemoveFromCart(id, username); }
if (response.success) { setLoading(true);
await refreshCart(); try {
showToast('Produit supprimé', 'success'); const response = await apiRemoveFromCart(id, username);
} else { if (response.success) {
showToast(response.message || 'Erreur suppression', 'error'); await refreshCart();
} showToast("Produit supprimé", "success");
} catch { } else {
showToast('Erreur suppression', 'error'); showToast(response.message || "Erreur suppression", "error");
} finally { }
setLoading(false); } catch {
} showToast("Erreur suppression", "error");
}; } finally {
setLoading(false);
}
};
const clearCartAction = async () => { const clearCartAction = async () => {
const username = await getUsername(); const username = await getUsername();
if (!username) { showToast('Vous devez être connecté.', 'warning'); return; } if (!username) {
setLoading(true); showToast("Vous devez être connecté.", "warning");
try { return;
const response = await apiClearCart(username); }
if (response.success) { setLoading(true);
setCartItems([]); try {
showToast(response.message || 'Panier vidé', 'success'); const response = await apiClearCart(username);
} else { if (response.success) {
showToast(response.message || 'Erreur vidage', 'error'); setCartItems([]);
} showToast(response.message || "Panier vidé", "success");
} catch { } else {
showToast('Erreur vidage', 'error'); showToast(response.message || "Erreur vidage", "error");
} finally { }
setLoading(false); } catch {
} showToast("Erreur vidage", "error");
}; } finally {
setLoading(false);
}
};
const cartCount = cartItems.length; const cartCount = cartItems.length;
const cartTotal = cartItems.reduce((sum, item) => sum + item.price, 0); const cartTotal = cartItems.reduce((sum, item) => sum + item.price, 0);
return ( return (
<CartContext.Provider value={{ <CartContext.Provider
cartItems, addToCart, removeFromCart, clearCart: clearCartAction, value={{
cartCount, cartTotal, loading, refreshCart, toast, clearToast, isAuthenticated, cartItems,
}}> addToCart,
{children} removeFromCart,
</CartContext.Provider> clearCart: clearCartAction,
); cartCount,
cartTotal,
loading,
refreshCart,
toast,
clearToast,
isAuthenticated,
}}
>
{children}
</CartContext.Provider>
);
} }
export function useCart() { export function useCart() {
const context = useContext(CartContext); const context = useContext(CartContext);
if (!context) throw new Error('useCart must be used within a CartProvider'); if (!context) throw new Error("useCart must be used within a CartProvider");
return context; return context;
} }
@@ -67,7 +67,6 @@ function ClientTabs() {
const navigation = useNavigation<any>(); const navigation = useNavigation<any>();
const [notifModalVisible, setNotifModalVisible] = useState(false); const [notifModalVisible, setNotifModalVisible] = useState(false);
// Naviguer vers le suivi quand on tap une push notification
useEffect(() => { useEffect(() => {
if (navigateToOrder) { if (navigateToOrder) {
setNotifModalVisible(false); setNotifModalVisible(false);
@@ -77,7 +76,6 @@ function ClientTabs() {
}, [navigateToOrder, navigation, clearNavigateToOrder]); }, [navigateToOrder, navigation, clearNavigateToOrder]);
const handleLogout = async () => { const handleLogout = async () => {
// Supprimer le push token du backend avant logout
if (pushToken) { if (pushToken) {
await removePushTokenFromBackend(pushToken); await removePushTokenFromBackend(pushToken);
} }
@@ -137,7 +135,6 @@ function ClientTabs() {
gap: spacing.m, gap: spacing.m,
}} }}
> >
{/* Cloche notifications */}
<TouchableOpacity <TouchableOpacity
onPress={openNotifModal} onPress={openNotifModal}
style={{ position: "relative" }} style={{ position: "relative" }}
@@ -247,7 +244,6 @@ function ClientTabs() {
/> />
</Tab.Navigator> </Tab.Navigator>
{/* Modal notifications */}
<Modal <Modal
visible={notifModalVisible} visible={notifModalVisible}
animationType="slide" animationType="slide"