chore: transfer repo
This commit is contained in:
157
components/ui/ProductCard.tsx
Normal file
157
components/ui/ProductCard.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user