244 lines
8.4 KiB
TypeScript
244 lines
8.4 KiB
TypeScript
import React, { useState } from 'react'
|
|
import { useNavigate } from 'react-router-dom'
|
|
import { ShoppingCart, Star } from 'lucide-react'
|
|
|
|
// Import gambar produk
|
|
import cabaiKeringImg from '../fotoProduk/cabai jawa kering.jpg'
|
|
import cabaiBasahImg from '../fotoProduk/cabai jawa.jpg'
|
|
import tehImg from '../fotoProduk/teh.webp'
|
|
import bubukImg from '../fotoProduk/bubuk.jpg'
|
|
|
|
interface Product {
|
|
id: number
|
|
name: string
|
|
description: string
|
|
price: string
|
|
unit: string
|
|
image?: string // Ubah dari emoji ke image
|
|
emoji?: string // Keep emoji sebagai fallback
|
|
badge?: string
|
|
rating: number
|
|
reviews: number
|
|
bgColor: string
|
|
}
|
|
|
|
const PRODUCTS: Product[] = [
|
|
{ id: 1, name: 'Cabai Jawa Kering Premium', description: 'Dikeringkan pada suhu presisi untuk mempertahankan warna dan aroma.', price: 'Rp 85.000', unit: '1000g', image: cabaiKeringImg, badge: 'TERLARIS', rating: 4.9, reviews: 128, bgColor: 'linear-gradient(135deg,#8B1A0A,#C0392B)' },
|
|
{ id: 2, name: 'Cabai Jawa', description: 'Proses higienis, warna dan rasa alami terjaga sepanjang proses pengeringan.', price: 'Rp 30.000', unit: '100g', image: cabaiBasahImg, rating: 4.7, reviews: 84, bgColor: 'linear-gradient(135deg,#5c3a1e,#8b5e3c)' },
|
|
{ id: 3, name: 'Teh Rempah Hangat', description: 'Campuran herbal pilihan untuk kesehatan yang menyegarkan dan menyehatkan.', price: 'Rp 55.000', unit: 'pack', image: tehImg, badge: 'BARU', rating: 4.8, reviews: 56, bgColor: 'linear-gradient(135deg,#4a3220,#7a5c3a)' },
|
|
{ id: 4, name: 'Bubuk Cabai Jawa', description: 'Cabai jawa pilihan kaya antioksidan, diproses tanpa bahan pengawet.', price: 'Rp 135.000', unit: '1000g', image: bubukImg, rating: 4.6, reviews: 72, bgColor: 'linear-gradient(135deg,#7a2010,#b84030)' },
|
|
]
|
|
|
|
const CATEGORIES = []
|
|
|
|
function ProductCard({ product, index }: { product: Product; index: number }) {
|
|
const [added, setAdded] = useState(false)
|
|
const [hovered, setHovered] = useState(false)
|
|
|
|
function handleAdd() {
|
|
setAdded(true)
|
|
setTimeout(() => setAdded(false), 1500)
|
|
}
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
background: 'white',
|
|
borderRadius: '20px',
|
|
overflow: 'hidden',
|
|
boxShadow: hovered ? '0 14px 44px rgba(45,74,30,0.15)' : '0 2px 20px rgba(45,74,30,0.06)',
|
|
border: '1px solid rgba(74,124,47,0.08)',
|
|
transform: hovered ? 'translateY(-6px)' : 'translateY(0)',
|
|
transition: 'transform 0.3s, box-shadow 0.3s',
|
|
animation: `fadeUp 0.5s ease ${index * 0.08}s both`,
|
|
}}
|
|
onMouseEnter={() => setHovered(true)}
|
|
onMouseLeave={() => setHovered(false)}
|
|
>
|
|
{/* Image area */}
|
|
<div
|
|
style={{
|
|
height: '175px',
|
|
background: product.bgColor,
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
position: 'absolute', top: '12px', left: '12px',
|
|
width: '26px', height: '26px',
|
|
background: 'rgba(0,0,0,0.28)',
|
|
borderRadius: '7px',
|
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
color: 'white', fontSize: '0.72rem', fontWeight: 700,
|
|
}}
|
|
>
|
|
{product.id}
|
|
</div>
|
|
{product.badge && (
|
|
<div
|
|
style={{
|
|
position: 'absolute', top: '12px', right: '12px',
|
|
background: product.badge === 'TERLARIS' ? '#d48c2a' : '#4a7c2f',
|
|
color: 'white', fontSize: '0.62rem', fontWeight: 700,
|
|
padding: '3px 9px', borderRadius: '6px', letterSpacing: '0.04em',
|
|
}}
|
|
>
|
|
{product.badge}
|
|
</div>
|
|
)}
|
|
{/* Tampilkan gambar jika ada, kalau tidak ada gunakan emoji */}
|
|
{product.image ? (
|
|
<img
|
|
src={product.image}
|
|
alt={product.name}
|
|
style={{
|
|
width: '100%',
|
|
height: '100%',
|
|
objectFit: 'cover',
|
|
transition: 'transform 0.3s',
|
|
transform: hovered ? 'scale(1.05)' : 'scale(1)',
|
|
}}
|
|
/>
|
|
) : (
|
|
<span style={{ fontSize: '3.8rem', filter: 'drop-shadow(0 4px 12px rgba(0,0,0,0.3))' }}>
|
|
{product.emoji}
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
{/* Info */}
|
|
<div style={{ padding: '1.1rem' }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: '4px', marginBottom: '6px' }}>
|
|
<Star size={12} fill="#d48c2a" color="#d48c2a" />
|
|
<span style={{ fontSize: '0.76rem', fontWeight: 700, color: '#d48c2a' }}>{product.rating}</span>
|
|
<span style={{ fontSize: '0.74rem', color: '#a0a898' }}>({product.reviews})</span>
|
|
</div>
|
|
<h3 style={{ fontSize: '0.92rem', fontWeight: 700, color: '#1a2810', marginBottom: '5px', lineHeight: 1.3 }}>
|
|
{product.name}
|
|
</h3>
|
|
<p style={{ fontSize: '0.78rem', color: '#7a8a6a', lineHeight: 1.5, marginBottom: '1rem' }}>
|
|
{product.description}
|
|
</p>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
|
<div>
|
|
<span style={{ fontSize: '1rem', fontWeight: 800, color: '#1a2810' }}>{product.price}</span>
|
|
<span style={{ fontSize: '0.74rem', color: '#a0a898' }}> / {product.unit}</span>
|
|
</div>
|
|
<button
|
|
onClick={handleAdd}
|
|
style={{
|
|
background: added
|
|
? 'linear-gradient(135deg,#4a7c2f,#7ab648)'
|
|
: 'linear-gradient(135deg,#d48c2a,#f0b855)',
|
|
color: 'white',
|
|
padding: '7px 12px',
|
|
borderRadius: '10px',
|
|
fontSize: '0.74rem',
|
|
fontWeight: 700,
|
|
display: 'flex', alignItems: 'center', gap: '5px',
|
|
transition: 'all 0.3s',
|
|
border: 'none',
|
|
cursor: 'pointer',
|
|
whiteSpace: 'nowrap',
|
|
}}
|
|
>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function CategoryBtn({ label, active, onClick }: { label: string; active: boolean; onClick: () => void }) {
|
|
return (
|
|
<button
|
|
onClick={onClick}
|
|
style={{
|
|
padding: '7px 16px', borderRadius: '20px',
|
|
fontSize: '0.82rem', fontWeight: 600,
|
|
border: active ? 'none' : '1px solid #e8eee0',
|
|
background: active ? 'linear-gradient(135deg,#2d4a1e,#4a7c2f)' : 'white',
|
|
color: active ? 'white' : '#4a5c3a',
|
|
cursor: 'pointer', transition: 'all 0.2s',
|
|
}}
|
|
>
|
|
{label}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
export default function ProductGrid() {
|
|
const [activeCategory, setActiveCategory] = useState('Semua')
|
|
|
|
return (
|
|
<section style={{ background: 'white', padding: '5rem 2rem' }}>
|
|
<div style={{ maxWidth: '1200px', margin: '0 auto' }}>
|
|
|
|
{/* Header row */}
|
|
<div
|
|
style={{
|
|
display: 'flex', justifyContent: 'flex-end', alignItems: 'flex-end',
|
|
marginBottom: '2.5rem', flexWrap: 'wrap', gap: '1rem',
|
|
}}
|
|
>
|
|
<div style={{ display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
|
|
{CATEGORIES.map((cat) => (
|
|
<CategoryBtn
|
|
key={cat} label={cat}
|
|
active={activeCategory === cat}
|
|
onClick={() => setActiveCategory(cat)}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Grid */}
|
|
<div
|
|
style={{
|
|
display: 'grid',
|
|
gridTemplateColumns: 'repeat(auto-fill,minmax(270px,1fr))',
|
|
gap: '1.4rem',
|
|
}}
|
|
>
|
|
{PRODUCTS.map((p, i) => <ProductCard key={p.id} product={p} index={i} />)}
|
|
</div>
|
|
|
|
{/* Load more */}
|
|
<LoadMoreBtn />
|
|
</div>
|
|
</section>
|
|
)
|
|
}
|
|
|
|
function LoadMoreBtn() {
|
|
const [hovered, setHovered] = useState(false)
|
|
const navigate = useNavigate()
|
|
|
|
function handleClick() {
|
|
navigate('/produk')
|
|
}
|
|
|
|
return (
|
|
<div style={{ textAlign: 'center', marginTop: '3rem' }}>
|
|
<button
|
|
onClick={handleClick}
|
|
style={{
|
|
background: hovered ? '#2d4a1e' : 'transparent',
|
|
border: '2px solid #2d4a1e',
|
|
color: hovered ? 'white' : '#2d4a1e',
|
|
padding: '12px 36px', borderRadius: '12px',
|
|
fontSize: '0.9rem', fontWeight: 700, cursor: 'pointer',
|
|
transition: 'all 0.2s',
|
|
}}
|
|
onMouseEnter={() => setHovered(true)}
|
|
onMouseLeave={() => setHovered(false)}
|
|
>
|
|
Lihat Semua Produk
|
|
</button>
|
|
</div>
|
|
)
|
|
}
|