feat: add active modal image state and thumbnail update logic to product display

This commit is contained in:
Yoga Pangestu 2026-04-24 00:14:08 +07:00
parent 530d2cbbcb
commit b7f3953a56

View File

@ -10,6 +10,13 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
const [allProducts, setAllProducts] = useState<any[]>(bestSellers.data);
const [search, setSearch] = useState('');
const [selectedCategorySlug, setSelectedCategorySlug] = useState('');
const [activeModalImage, setActiveModalImage] = useState<string | null>(null);
useEffect(() => {
if (selectedProduct) {
setActiveModalImage(selectedProduct?.thumbnail_url);
}
}, [selectedProduct]);
useEffect(() => {
const timer = setTimeout(() => {
@ -154,20 +161,18 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
<div className="relative mb-8">
<div className="custom-scrollbar flex max-h-[300px] flex-col overflow-y-auto border-y border-[#1e4a6d]/20">
{categories.map((cat: any) => (
<button
key={cat.id}
<button
key={cat.id}
onClick={(e) => {
setSelectedCategorySlug(cat.slug);
scrollToSection(e, '#product');
}}
className={`group flex items-center justify-between border-b border-[#1e4a6d]/10 px-4 py-4 text-left text-xs font-bold uppercase tracking-wider transition-all hover:bg-[#1e4a6d] hover:text-white last:border-0 ${
selectedCategorySlug === cat.slug ? 'bg-[#1e4a6d] text-white' : ''
}`}
className={`group flex items-center justify-between border-b border-[#1e4a6d]/10 px-4 py-4 text-left text-xs font-bold uppercase tracking-wider transition-all hover:bg-[#1e4a6d] hover:text-white last:border-0 ${selectedCategorySlug === cat.slug ? 'bg-[#1e4a6d] text-white' : ''
}`}
>
{cat.name}
<ArrowRight size={14} className={`transition-all group-hover:translate-x-1 group-hover:opacity-100 ${
selectedCategorySlug === cat.slug ? 'opacity-100 translate-x-1' : 'opacity-0'
}`} />
<ArrowRight size={14} className={`transition-all group-hover:translate-x-1 group-hover:opacity-100 ${selectedCategorySlug === cat.slug ? 'opacity-100 translate-x-1' : 'opacity-0'
}`} />
</button>
))}
{categories.length === 0 && (
@ -219,7 +224,7 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
onClick={() => setSelectedProduct(product)}
>
<img
src={product.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
src={product?.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
alt={product.name}
className="h-full w-full object-cover"
/>
@ -247,7 +252,7 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
{/* Category Filter */}
<div className="relative">
<select
<select
value={selectedCategorySlug}
onChange={(e) => setSelectedCategorySlug(e.target.value)}
className="appearance-none border border-[#1e4a6d]/20 bg-transparent py-2 pl-4 pr-10 text-[10px] font-bold uppercase tracking-widest outline-none transition-all focus:border-[#1e4a6d] cursor-pointer"
@ -261,13 +266,13 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
<div className="h-1 w-1 rotate-45 border-b border-r border-[#1e4a6d]"></div>
</div>
</div>
{/* Search Input */}
<div className="relative flex items-center">
<Search size={14} className="absolute left-3 opacity-40" />
<input
type="text"
placeholder="Cari produk..."
<input
type="text"
placeholder="Cari produk..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="border border-[#1e4a6d]/20 bg-transparent py-2 pl-10 pr-4 text-[10px] font-bold uppercase tracking-widest outline-none transition-all focus:border-[#1e4a6d] w-full sm:w-[200px]"
@ -288,7 +293,7 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
onClick={() => setSelectedProduct(item)}
>
<img
src={item.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
src={item?.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
alt={item.name}
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-110"
/>
@ -305,8 +310,8 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
{item.name}
</p>
<p className="mb-4 text-sm font-medium opacity-60">{formatCurrency(item.retail_price)}</p>
<a
<a
href={`https://wa.me/628123456789?text=${encodeURIComponent(`Halo VN Grup, saya ingin memesan ${item.name} seharga ${formatCurrency(item.retail_price)}. Mohon info detail pembayarannya.`)}`}
target="_blank"
rel="noopener noreferrer"
@ -324,7 +329,7 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
</div>
<h3 className="mb-2 text-xl font-medium">Produk tidak ditemukan</h3>
<p className="mb-8 text-sm opacity-60">Coba gunakan kata kunci lain atau periksa ejaan Anda.</p>
<button
<button
onClick={() => {
setSearch('');
setSelectedCategorySlug('');
@ -501,24 +506,47 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
<div className="grid grid-cols-1 md:grid-cols-2">
{/* Product Images */}
<div className="border-b border-[#1e4a6d]/10 md:border-b-0 md:border-r overflow-hidden bg-white">
<div className="aspect-[4/5] overflow-hidden">
<div className="border-b border-[#1e4a6d]/10 md:border-b-0 md:border-r overflow-hidden bg-[#fdfcf9]">
<div className="aspect-[4/5] overflow-hidden relative group/hero">
<img
src={selectedProduct?.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
src={activeModalImage || selectedProduct?.thumbnail_url || 'https://images.unsplash.com/photo-1719947348940-7aa339028cbc?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDgzfHx8ZW58MHx8fHx8'}
alt={selectedProduct?.name}
className="h-full w-full object-cover"
className="h-full w-full object-cover transition-transform duration-700 hover:scale-105"
/>
{/* Blueprint overlay decoration */}
<div className="absolute top-4 left-4 text-[8px] font-mono opacity-20 pointer-events-none">DET_V.1.0</div>
</div>
{/* Image Gallery if exists */}
{selectedProduct?.images_data?.length > 0 && (
<div className="flex border-t border-[#1e4a6d]/10">
{selectedProduct.images_data.map((img: any, i: number) => (
<div key={i} className="aspect-square w-20 border-r border-[#1e4a6d]/10 overflow-hidden">
<img src={img.url} alt="detail" className="h-full w-full object-cover opacity-60 hover:opacity-100 transition-opacity cursor-pointer" />
{/* Refined Image Gallery List */}
<div className="p-4 border-t border-[#1e4a6d]/10">
<p className="text-[8px] font-bold uppercase tracking-[0.2em] mb-3 opacity-40">Galeri Foto</p>
<div className="flex flex-wrap gap-3">
{/* Thumbnail (Main Image) */}
<div
onClick={() => setActiveModalImage(selectedProduct?.thumbnail_url)}
className={`relative aspect-square w-14 cursor-pointer overflow-hidden transition-all duration-300 ${activeModalImage === selectedProduct?.thumbnail_url
? 'ring-1 ring-[#1e4a6d] ring-offset-2'
: 'opacity-40 hover:opacity-100'
}`}
>
<img src={selectedProduct?.thumbnail_url} className="h-full w-full object-cover" alt="main" />
</div>
{/* Additional Images */}
{selectedProduct?.images_data?.map((img: any, i: number) => (
<div
key={i}
onClick={() => setActiveModalImage(img.url)}
className={`relative aspect-square w-14 cursor-pointer overflow-hidden transition-all duration-300 ${activeModalImage === img.url
? 'ring-1 ring-[#1e4a6d] ring-offset-2'
: 'opacity-40 hover:opacity-100'
}`}
>
<img src={img.url} className="h-full w-full object-cover" alt={`view ${i + 1}`} />
</div>
))}
</div>
)}
</div>
</div>
{/* Product Info */}
@ -541,7 +569,7 @@ export default function Homepage({ categories = [], bestSellers, topSellingProdu
</div>
<div className="mt-auto pt-8 border-t border-[#1e4a6d]/10">
<a
<a
href={`https://wa.me/628123456789?text=${encodeURIComponent(`Halo VN Grup, saya tertarik dengan produk ${selectedProduct?.name} seharga ${formatCurrency(selectedProduct?.retail_price || 0)}. Bisa tanya-tanya dulu?`)}`}
target="_blank"
rel="noopener noreferrer"