Files
309aa2d1-6efc-4562-87fc-866…/src/components/sections/product/ProductCardThree.tsx

157 lines
5.1 KiB
TypeScript

'use client';
import React, { useState } from 'react';
import { Heart, ShoppingCart } from 'lucide-react';
import { cn } from '@/lib/utils';
export interface ProductCard {
id: string;
name: string;
price: string;
imageSrc: string;
imageAlt?: string;
rating: number;
reviewCount: string;
isFavorited?: boolean;
onFavorite?: () => void;
onProductClick?: () => void;
}
interface ProductCardThreeProps {
products?: ProductCard[];
carouselMode?: 'auto' | 'buttons';
gridVariant: 'uniform-all-items-equal' | 'bento-grid' | 'bento-grid-inverted' | 'two-columns-alternating-heights' | 'asymmetric-60-wide-40-narrow' | 'three-columns-all-equal-width' | 'four-items-2x2-equal-grid';
animationType: 'none' | 'opacity' | 'slide-up' | 'scale-rotate' | 'blur-reveal';
uniformGridCustomHeightClasses?: string;
title: string;
titleSegments?: Array<{ type: 'text'; content: string } | { type: 'image'; src: string; alt?: string }>;
description: string;
tag?: string;
tagIcon?: React.ComponentType<any>;
tagAnimation?: 'none' | 'opacity' | 'slide-up' | 'blur-reveal';
buttons?: Array<{ text: string; onClick?: () => void; href?: string }>;
buttonAnimation?: 'none' | 'opacity' | 'slide-up' | 'blur-reveal';
textboxLayout: 'default' | 'split' | 'split-actions' | 'split-description' | 'inline-image';
useInvertedBackground: boolean;
ariaLabel?: string;
className?: string;
containerClassName?: string;
cardClassName?: string;
imageClassName?: string;
textBoxTitleClassName?: string;
textBoxTitleImageWrapperClassName?: string;
textBoxTitleImageClassName?: string;
textBoxDescriptionClassName?: string;
cardBrandClassName?: string;
cardNameClassName?: string;
cardPriceClassName?: string;
cardRatingClassName?: string;
actionButtonClassName?: string;
gridClassName?: string;
carouselClassName?: string;
controlsClassName?: string;
textBoxClassName?: string;
textBoxTagClassName?: string;
textBoxButtonContainerClassName?: string;
textBoxButtonClassName?: string;
textBoxButtonTextClassName?: string;
}
export const ProductCardThree: React.FC<ProductCardThreeProps> = ({
products = [],
gridVariant,
animationType,
title,
description,
textboxLayout,
useInvertedBackground,
ariaLabel = 'Product section',
className,
containerClassName,
cardClassName,
imageClassName,
}) => {
const [favorites, setFavorites] = useState<Set<string>>(new Set());
const toggleFavorite = (productId: string) => {
const newFavorites = new Set(favorites);
if (newFavorites.has(productId)) {
newFavorites.delete(productId);
} else {
newFavorites.add(productId);
}
setFavorites(newFavorites);
};
const handleProductClick = (product: ProductCard) => {
product.onProductClick?.();
};
const renderStars = (rating: number) => {
return (
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((star) => (
<span key={star} className={star <= rating ? 'text-yellow-400' : 'text-gray-300'}>
</span>
))}
</div>
);
};
return (
<div className={cn('product-card-three', containerClassName)} aria-label={ariaLabel}>
<div className="header">
<h2>{title}</h2>
<p>{description}</p>
</div>
<div className={cn('products-grid', gridClassName)}>
{products.map((product) => (
<div key={product.id} className={cn('product-card', cardClassName)}>
<div className="image-wrapper relative">
<img
src={product.imageSrc}
alt={product.imageAlt || product.name}
className={cn('w-full h-auto', imageClassName)}
/>
<button
onClick={() => toggleFavorite(product.id)}
className="absolute top-2 right-2 p-2 rounded-full bg-white/80 hover:bg-white transition-colors"
aria-label={`Toggle favorite for ${product.name}`}
>
<Heart
size={20}
className={cn(
'transition-colors',
favorites.has(product.id)
? 'fill-red-500 text-red-500'
: 'text-gray-400'
)}
/>
</button>
</div>
<div className="content">
<h3 className="text-lg font-semibold">{product.name}</h3>
<div className="flex items-center gap-2 mt-2">
{renderStars(product.rating)}
<span className="text-sm text-gray-600">({product.reviewCount})</span>
</div>
<p className="text-2xl font-bold mt-2">{product.price}</p>
<button
onClick={() => handleProductClick(product)}
className="mt-4 w-full px-4 py-2 bg-primary rounded hover:opacity-90 transition-opacity flex items-center justify-center gap-2"
>
<ShoppingCart size={18} />
Add to Cart
</button>
</div>
</div>
))}
</div>
</div>
);
};
export default ProductCardThree;