From 717e5dea765c0a97515a57150b2ef260b647419e Mon Sep 17 00:00:00 2001 From: kudindmitriy Date: Mon, 23 Mar 2026 18:19:49 +0200 Subject: [PATCH] Bob AI: Implement a 3D flip animation on hover for each product card --- .../sections/product/ProductCardThree.tsx | 125 +++++++++++++----- 1 file changed, 93 insertions(+), 32 deletions(-) diff --git a/src/components/sections/product/ProductCardThree.tsx b/src/components/sections/product/ProductCardThree.tsx index 12fc68e..8af4e6a 100644 --- a/src/components/sections/product/ProductCardThree.tsx +++ b/src/components/sections/product/ProductCardThree.tsx @@ -23,6 +23,7 @@ type ProductCard = Product & { onQuantityChange?: (quantity: number) => void; initialQuantity?: number; priceButtonProps?: Partial>; + ingredients?: string[]; // Added for flip card back }; interface ProductCardThreeProps { @@ -62,6 +63,30 @@ interface ProductCardThreeProps { textBoxButtonTextClassName?: string; } +// Helper function to generate ingredients based on product name +const generateIngredients = (productName: string): string[] => { + productName = productName.toLowerCase(); + if (productName.includes("croissant")) { + return ["Wheat Flour", "Butter", "Water", "Sugar", "Yeast", "Salt", "Milk"]; + } + if (productName.includes("cupcake")) { + return ["All-Purpose Flour", "Sugar", "Eggs", "Milk", "Butter", "Baking Powder", "Vanilla Extract", "Salt", "Icing Sugar"]; + } + if (productName.includes("sourdough")) { + return ["Bread Flour", "Water", "Sourdough Starter", "Salt"]; + } + if (productName.includes("cake")) { + return ["All-Purpose Flour", "Sugar", "Eggs", "Butter", "Milk", "Cocoa Powder", "Baking Soda", "Vanilla Extract", "Cream Cheese Frosting"]; + } + if (productName.includes("bread")) { + return ["Wheat Flour", "Water", "Yeast", "Salt", "Sugar"]; + } + if (productName.includes("pastry")) { + return ["Flour", "Butter", "Sugar", "Eggs", "Milk", "Fruit Filling"]; + } + // Default ingredients for other products + return ["Flour", "Sugar", "Eggs", "Butter", "Milk", "Baking Powder", "Vanilla Extract"]; +}; interface ProductCardItemProps { product: ProductCard; @@ -86,6 +111,7 @@ const ProductCardItem = memo(({ }: ProductCardItemProps) => { const theme = useTheme(); const [quantity, setQuantity] = useState(product.initialQuantity || 1); + const ingredients = product.ingredients || generateIngredients(product.name); const handleIncrement = useCallback((e: React.MouseEvent) => { e.stopPropagation(); @@ -103,60 +129,95 @@ const ProductCardItem = memo(({ } }, [quantity, product]); - const handleClick = useCallback(() => { + const handleViewDetailsClick = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); // Prevent any parent click handlers + product.onProductClick?.(); // This will navigate to /shop/:id or trigger static product action + }, [product]); + + const handleBuyClick = useCallback((e: React.MouseEvent) => { + e.stopPropagation(); // Prevent any parent click handlers if (isFromApi && onBuyClick) { onBuyClick(product.id, quantity); } else { - product.onProductClick?.(); + console.log(`Buying ${quantity} of ${product.name}`); } }, [isFromApi, onBuyClick, product, quantity]); return (
- +
+ {/* Front of the card */} +
+ -
-

- {product.name} -

+
+

+ {product.name} +

-
-
- - - {quantity} - - +
+
+ + + {quantity} + + +
+ +
+
+ {/* Back of the card */} +
+
+

Ingredients:

+
    + {ingredients.map((ingredient, i) => ( +
  • {ingredient}
  • + ))} +
+
-- 2.49.1