Files
vula-b60f0248/src/components/sections/BestsellersGridSection.tsx
T
Vula Builder fc233a923a Deploy
2026-07-28 12:39:43 +00:00

74 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client'
import { useMedusaProducts } from '@/hooks/useMedusaProducts'
import { useMedusaCart } from '@/hooks/useMedusaCart'
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/Card'
import Button from '@/components/ui/Button'
import Badge from '@/components/ui/Badge'
import Image from 'next/image'
import Link from 'next/link'
import { ShoppingBag, Zap } from 'lucide-react'
export default function BestsellersGridSection() {
const { products, isLoading } = useMedusaProducts(4)
const { addToCart } = useMedusaCart()
const formatPrice = (amount: number, code?: string) => {
const symbols: Record<string, string> = { zar: 'R', usd: '$', eur: '€', gbp: '£', kes: 'KSh', ngn: '₦', ghs: '₵' }
const sym = symbols[(code ?? '').toLowerCase()] ?? (code?.toUpperCase() ?? '')
return `${sym}${(amount / 100).toFixed(2)}`
}
if (isLoading) return <div className="flex justify-center py-16"><div className="w-8 h-8 rounded-full border-2 border-current border-t-transparent animate-spin" /></div>
if (!products || products.length === 0) return null
const handleAddToCart = (variantId: string) => {
addToCart(variantId, 1)
window.dispatchEvent(new CustomEvent('cart-drawer-open'))
}
return (
<section data-vula-section="bestsellersgrid" id="bestsellers" className="py-20 bg-white">
<div className="container mx-auto px-4">
<div className="text-center mb-12">
<p className="text-sm uppercase tracking-widest text-[#8b5a3c] mb-2">Amandla Popular</p>
<h2 className="text-3xl md:text-4xl font-bold text-[#2c331f]">Bestsellers</h2>
<p className="text-[#8b5a3c] mt-3 max-w-xl mx-auto">Our community's most-loved rituals tried, tested, and adored across South Africa.</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{products.slice(0, 4).map((product) => {
const variant = product.variants?.[0]
const price = variant?.prices?.[0]
const imgSrc = product.thumbnail || '/placeholder-product.svg'
return (
<Card key={product.id} className="rounded-2xl border-none shadow-lg hover:shadow-xl transition-shadow duration-300 overflow-hidden bg-[#f4f5f2]">
<div className="relative">
<Link href={`/products/${product.id}`} className="block relative aspect-square overflow-hidden">
<Image src={imgSrc} alt={product.title} fill className="object-cover hover:scale-105 transition-transform duration-500" sizes="(max-width: 768px) 100vw, 300px" />
</Link>
<Badge variant="accent" className="absolute top-3 left-3 bg-[#ea580c] text-white text-xs px-2 py-1 rounded-full">
<Zap className="w-3 h-3 inline mr-1" />Bestseller
</Badge>
</div>
<CardContent className="p-4 pb-2">
<Link href={`/products/${product.id}`} className="hover:underline">
<h3 className="font-semibold text-[#2c331f] text-lg truncate">{product.title}</h3>
</Link>
{price && (
<p className="text-[#ea580c] font-bold mt-1">{formatPrice(price.amount, price.currency_code)}</p>
)}
</CardContent>
<CardFooter className="p-4 pt-0">
{variant && (
<Button variant="default" size="sm" className="w-full bg-[#6b8e23] hover:bg-[#5a7a1e] text-white" onClick={() => handleAddToCart(variant.id)}>
<ShoppingBag className="w-4 h-4 mr-2" /> Add to Cart
</Button>
)}
</CardFooter>
</Card>
)
})}
</div>
</div>
</section>
)
}