156 lines
6.2 KiB
TypeScript
156 lines
6.2 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from 'react'
|
|
import Link from 'next/link'
|
|
import { getCategoryImage, formatPrice, type Product } from '@homaroma/types'
|
|
import { useCartStore } from '../store/cartStore'
|
|
import { resolveCategoryName, resolveLocalized } from '../lib/localization'
|
|
import { useLang } from '../hooks/useLang'
|
|
|
|
interface Props {
|
|
product: Product
|
|
}
|
|
|
|
export default function AddToCartSection({ product }: Props) {
|
|
const [selectedVariant, setSelectedVariant] = useState(0)
|
|
const { addToCart, toggleCart } = useCartStore()
|
|
const lang = useLang()
|
|
|
|
const currentVariant = product.variants[selectedVariant]
|
|
const categoryName = resolveCategoryName(product.category, lang)
|
|
const productName = resolveLocalized(product.name, lang) || product.scent.name
|
|
const description = resolveLocalized(product.description, lang)
|
|
|
|
const handleAddToCart = () => {
|
|
if (!currentVariant) return
|
|
|
|
addToCart({
|
|
productId: product.id,
|
|
variantId: currentVariant.id,
|
|
quantity: 1,
|
|
price: currentVariant.price || product.price || 0,
|
|
productName,
|
|
variantSize: currentVariant.size,
|
|
productImage: product.images?.[0]?.url || product.category.imageUrl || getCategoryImage(categoryName),
|
|
})
|
|
toggleCart(true)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="space-y-8">
|
|
<div className="space-y-2">
|
|
{categoryName && (
|
|
<p className="text-xs font-bold uppercase tracking-[0.28em] text-pop-pink">
|
|
{categoryName}
|
|
</p>
|
|
)}
|
|
<h1 className="text-4xl font-semibold leading-tight text-pop-black md:text-6xl">
|
|
{productName}
|
|
</h1>
|
|
<p className="text-sm font-semibold uppercase tracking-widest text-gray-500">
|
|
Premium Collection
|
|
</p>
|
|
</div>
|
|
|
|
{description && <p className="leading-relaxed text-gray-600">{description}</p>}
|
|
|
|
<div className="flex items-baseline gap-3">
|
|
<span className="text-4xl font-bold text-pop-pink">
|
|
{formatPrice(currentVariant?.price ?? product.price)}
|
|
</span>
|
|
{currentVariant && <span className="text-sm text-gray-500">/ {currentVariant.size}</span>}
|
|
</div>
|
|
|
|
{product.variants.length > 0 && (
|
|
<div className="space-y-3">
|
|
<p className="text-xs font-bold uppercase tracking-widest text-gray-500">Select Size</p>
|
|
<div className="flex flex-wrap gap-3">
|
|
{product.variants.map((variant, index) => (
|
|
<button
|
|
key={variant.id}
|
|
onClick={() => setSelectedVariant(index)}
|
|
className={`rounded-xl border px-5 py-3 text-sm font-bold uppercase tracking-widest transition ${
|
|
selectedVariant === index
|
|
? 'border-pop-pink bg-pop-pink text-white shadow-brutal'
|
|
: 'border-gray-200 bg-white text-gray-600 hover:border-pop-pink hover:text-pop-pink'
|
|
}`}
|
|
>
|
|
{variant.size}
|
|
<span className={`mt-1 block text-[10px] ${selectedVariant === index ? 'text-white/80' : 'text-gray-400'}`}>
|
|
{formatPrice(variant.price)}
|
|
</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="hidden gap-4 md:flex">
|
|
<button
|
|
onClick={handleAddToCart}
|
|
className="flex-1 rounded-full bg-pop-black px-8 py-4 font-bold uppercase tracking-widest text-white transition hover:bg-pop-pink"
|
|
>
|
|
Add to Cart
|
|
</button>
|
|
{categoryName && (
|
|
<Link
|
|
href={`/category/${product.category.id}`}
|
|
className="rounded-full border border-gray-200 bg-white px-8 py-4 font-bold uppercase tracking-widest text-gray-600 transition hover:border-pop-pink hover:text-pop-pink"
|
|
>
|
|
{categoryName}
|
|
</Link>
|
|
)}
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-4 border-t border-gray-200 pt-6 text-sm text-gray-500">
|
|
<div>
|
|
<span className="mb-1 block text-xs font-bold uppercase tracking-widest text-gray-400">Scent</span>
|
|
<span className="font-semibold text-pop-black">{product.scent.name}</span>
|
|
</div>
|
|
<div>
|
|
<span className="mb-1 block text-xs font-bold uppercase tracking-widest text-gray-400">Category</span>
|
|
<Link href={`/category/${product.category.id}`} className="font-semibold text-pop-black transition hover:text-pop-pink">
|
|
{categoryName}
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="fixed bottom-0 left-0 right-0 z-40 border-t border-gray-200 bg-white/95 p-4 shadow-[0_-10px_30px_rgba(0,0,0,0.08)] backdrop-blur md:hidden">
|
|
{product.variants.length > 1 && (
|
|
<div className="mb-3 flex gap-2 overflow-x-auto pb-1" style={{ scrollbarWidth: 'none' }}>
|
|
{product.variants.map((variant, index) => (
|
|
<button
|
|
key={`mobile-v-${variant.id}`}
|
|
onClick={() => setSelectedVariant(index)}
|
|
className={`flex-shrink-0 rounded-full border px-4 py-2 text-[10px] font-bold uppercase tracking-widest transition ${
|
|
selectedVariant === index
|
|
? 'border-pop-pink bg-pop-pink text-white'
|
|
: 'border-gray-200 bg-white text-gray-500'
|
|
}`}
|
|
>
|
|
{variant.size}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
<div className="flex items-center justify-between gap-4">
|
|
<div className="flex flex-col">
|
|
<span className="text-[10px] font-bold uppercase tracking-widest text-gray-400">
|
|
{product.variants.length > 1 ? currentVariant?.size : 'Total Price'}
|
|
</span>
|
|
<span className="text-xl font-bold text-pop-pink">{formatPrice(currentVariant?.price ?? product.price)}</span>
|
|
</div>
|
|
<button
|
|
onClick={handleAddToCart}
|
|
className="flex-1 rounded-full bg-pop-black px-5 py-3.5 font-bold uppercase tracking-widest text-white transition hover:bg-pop-pink"
|
|
>
|
|
Add to Cart
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</>
|
|
)
|
|
}
|