157 lines
5.3 KiB
TypeScript
157 lines
5.3 KiB
TypeScript
'use client';
|
|
|
|
import { AddToBoxButton } from '@/components/products/AddToBoxButton';
|
|
import { ColorVariant, getProductColorVariants } from '@/components/products/utils/colorUtils';
|
|
import { Product } from 'lib/shopify/types';
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { usePathname } from 'next/navigation';
|
|
import { useEffect, useState } from 'react';
|
|
import { AddToCartButton } from './AddToCartButton';
|
|
import { ColorSelector } from './ColorSelector';
|
|
|
|
interface ProductCardProps {
|
|
title: string;
|
|
variant: string;
|
|
price: number;
|
|
imageSrc: string;
|
|
slug: string;
|
|
product?: Product;
|
|
colors?: string[]; // Array of color hex codes
|
|
}
|
|
|
|
export function ProductCard({ title, variant, price: defaultPrice, imageSrc, slug, product, colors }: ProductCardProps) {
|
|
const pathname = usePathname();
|
|
const isBuildBoxPage = pathname.includes('/build-box');
|
|
|
|
const [colorVariants, setColorVariants] = useState<ColorVariant[] | undefined>(undefined);
|
|
const [selectedColorHex, setSelectedColorHex] = useState<string | null>(null);
|
|
const [selectedVariant, setSelectedVariant] = useState<ColorVariant | undefined>(undefined);
|
|
const [currentPrice, setCurrentPrice] = useState<number>(defaultPrice);
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
|
|
// Initialize color variants and selected color
|
|
useEffect(() => {
|
|
if (product) {
|
|
const variants = getProductColorVariants(product);
|
|
setColorVariants(variants);
|
|
|
|
if (variants && variants.length > 0) {
|
|
// Only set these values if we have valid variants
|
|
if (variants[0]?.color) {
|
|
setSelectedColorHex(variants[0].color);
|
|
}
|
|
setSelectedVariant(variants[0]);
|
|
if (typeof variants[0]?.price === 'number') {
|
|
setCurrentPrice(variants[0].price);
|
|
}
|
|
}
|
|
} else if (colors && colors.length > 0) {
|
|
// If we only have color hex codes without variants
|
|
const firstColor = colors[0];
|
|
if (firstColor) {
|
|
setSelectedColorHex(firstColor);
|
|
}
|
|
}
|
|
}, [product, colors]);
|
|
|
|
// Handle color selection
|
|
const handleColorSelect = (color: string) => {
|
|
setSelectedColorHex(color);
|
|
|
|
if (colorVariants) {
|
|
const variant = colorVariants.find(v => v.color === color);
|
|
if (variant) {
|
|
setSelectedVariant(variant);
|
|
setCurrentPrice(variant.price);
|
|
}
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="flex flex-col h-full">
|
|
{/* Image container with fixed height and hover effect */}
|
|
<div
|
|
className="relative w-full h-[480px] bg-gray-100 mb-5 overflow-hidden"
|
|
onMouseEnter={() => setIsHovered(true)}
|
|
onMouseLeave={() => setIsHovered(false)}
|
|
>
|
|
<Link href={`/product/${slug}`}>
|
|
<Image
|
|
src={imageSrc}
|
|
alt={title}
|
|
fill
|
|
className="object-cover transition-opacity duration-300"
|
|
sizes="(max-width: 768px) 280px, 405px"
|
|
/>
|
|
</Link>
|
|
|
|
{/* Button - always visible on mobile, hover effect on desktop */}
|
|
{product && (
|
|
<>
|
|
{/* Mobile button - always visible */}
|
|
<div className="absolute bottom-6 left-5 right-5 md:hidden">
|
|
{isBuildBoxPage ? (
|
|
<AddToBoxButton
|
|
productId={product.id}
|
|
name={product.title}
|
|
price={currentPrice}
|
|
image={imageSrc}
|
|
variantId={selectedVariant?.variantId}
|
|
color={selectedColorHex || undefined}
|
|
/>
|
|
) : (
|
|
<AddToCartButton
|
|
product={product}
|
|
variantId={selectedVariant?.variantId}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* Desktop button - visible on hover */}
|
|
<div className={`absolute bottom-6 left-5 right-5 hidden md:block transition-opacity duration-300 ${isHovered ? 'opacity-100' : 'opacity-0'}`}>
|
|
{isBuildBoxPage ? (
|
|
<AddToBoxButton
|
|
productId={product.id}
|
|
name={product.title}
|
|
price={currentPrice}
|
|
image={imageSrc}
|
|
variantId={selectedVariant?.variantId}
|
|
color={selectedColorHex || undefined}
|
|
/>
|
|
) : (
|
|
<AddToCartButton
|
|
product={product}
|
|
variantId={selectedVariant?.variantId}
|
|
/>
|
|
)}
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex justify-between items-start">
|
|
<h3 className="font-bold text-[18px] leading-[28px]">{title}</h3>
|
|
<span className="font-bold text-[20px] leading-[28px] ml-2">{currentPrice} €</span>
|
|
</div>
|
|
|
|
{variant && (
|
|
<p className="text-[16px] leading-[26px] text-gray-600 mb-auto">{variant}</p>
|
|
)}
|
|
|
|
{colorVariants && colorVariants.length > 0 ? (
|
|
<ColorSelector
|
|
colors={colorVariants}
|
|
selectedColor={selectedColorHex}
|
|
onColorSelect={handleColorSelect}
|
|
/>
|
|
) : colors && colors.length > 0 ? (
|
|
<ColorSelector
|
|
colors={colors}
|
|
selectedColor={selectedColorHex}
|
|
onColorSelect={setSelectedColorHex}
|
|
/>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|