583 lines
38 KiB
TypeScript
583 lines
38 KiB
TypeScript
import { formatCurrency } from '@/lib/formatters';
|
|
import { Link, router } from '@inertiajs/react';
|
|
import { ArrowRight, Facebook, Instagram, Phone, Search, X } from 'lucide-react';
|
|
import { useEffect, useState } from 'react';
|
|
import { GeneralSetting } from '@/types/general-setting';
|
|
|
|
export default function Homepage({ categories = [], bestSellers, topSellingProducts = [], setting }: { categories: any[], bestSellers: any, topSellingProducts: any[], setting: GeneralSetting }) {
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
const [isScrolled, setIsScrolled] = useState(false);
|
|
const [selectedProduct, setSelectedProduct] = useState<any>(null);
|
|
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(() => {
|
|
const params: any = {};
|
|
if (search) params.search = search;
|
|
if (selectedCategorySlug) params.category = selectedCategorySlug;
|
|
|
|
router.get(window.location.pathname, params, {
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
only: ['bestSellers'],
|
|
onSuccess: (page: any) => {
|
|
setAllProducts(page.props.bestSellers.data);
|
|
}
|
|
});
|
|
}, 500);
|
|
|
|
return () => clearTimeout(timer);
|
|
}, [search]);
|
|
|
|
useEffect(() => {
|
|
const params: any = {};
|
|
if (search) params.search = search;
|
|
if (selectedCategorySlug) params.category = selectedCategorySlug;
|
|
|
|
router.get(window.location.pathname, params, {
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
only: ['bestSellers'],
|
|
onSuccess: (page: any) => {
|
|
setAllProducts(page.props.bestSellers.data);
|
|
}
|
|
});
|
|
}, [selectedCategorySlug]);
|
|
|
|
useEffect(() => {
|
|
if (bestSellers.current_page > 1) {
|
|
setAllProducts(prev => {
|
|
// Prevent duplicates if data already exists
|
|
const existingIds = new Set(prev.map(p => p.id));
|
|
const newProducts = bestSellers.data.filter((p: any) => !existingIds.has(p.id));
|
|
return [...prev, ...newProducts];
|
|
});
|
|
}
|
|
}, [bestSellers]);
|
|
|
|
const loadMore = () => {
|
|
if (bestSellers.next_page_url) {
|
|
router.get(bestSellers.next_page_url, {}, {
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
only: ['bestSellers'],
|
|
});
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const handleScroll = () => {
|
|
setIsScrolled(window.scrollY > 20);
|
|
};
|
|
window.addEventListener('scroll', handleScroll);
|
|
|
|
// Smooth scroll for anchor links
|
|
const observerOptions = {
|
|
threshold: 0.1
|
|
};
|
|
|
|
const observer = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
entry.target.classList.add('opacity-100', 'translate-y-0');
|
|
entry.target.classList.remove('opacity-0', 'translate-y-10');
|
|
}
|
|
});
|
|
}, observerOptions);
|
|
|
|
document.querySelectorAll('section').forEach(section => {
|
|
section.classList.add('transition-all', 'duration-1000', 'opacity-0', 'translate-y-10');
|
|
observer.observe(section);
|
|
});
|
|
|
|
return () => {
|
|
window.removeEventListener('scroll', handleScroll);
|
|
observer.disconnect();
|
|
};
|
|
}, []);
|
|
|
|
const scrollToSection = (e: React.MouseEvent<HTMLElement>, id: string) => {
|
|
e.preventDefault();
|
|
const element = document.querySelector(id);
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: 'smooth' });
|
|
setIsMenuOpen(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<style>{`
|
|
html {
|
|
scroll-behavior: smooth;
|
|
scroll-padding-top: 54px;
|
|
}
|
|
.custom-scrollbar::-webkit-scrollbar {
|
|
width: 2px;
|
|
}
|
|
.custom-scrollbar::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
.custom-scrollbar::-webkit-scrollbar-thumb {
|
|
background: #1e4a6d;
|
|
border-radius: 10px;
|
|
}
|
|
`}</style>
|
|
<div className="min-h-screen scroll-smooth bg-[#f7f3eb] font-serif text-[#1e4a6d] selection:bg-[#1e4a6d] selection:text-white">
|
|
{/* Navbar */}
|
|
<header className={`sticky top-0 z-50 border-b border-[#1e4a6d]/10 transition-all duration-300 ${isScrolled ? 'bg-[#f7f3eb]/80 py-3 backdrop-blur-md' : 'bg-transparent py-5'
|
|
}`}>
|
|
<div className="mx-auto flex max-w-7xl items-center justify-between px-6 lg:px-12">
|
|
<div className="flex items-center gap-2 text-xl font-bold uppercase tracking-tighter">
|
|
{setting?.logo_light_url ? (
|
|
<img
|
|
src={setting.logo_light_url}
|
|
alt={setting.site_name}
|
|
className="max-h-8 w-auto"
|
|
/>
|
|
) : (
|
|
setting?.site_name || 'VN Grup'
|
|
)}
|
|
</div>
|
|
|
|
<nav className="hidden items-center gap-10 text-[10px] font-bold uppercase tracking-[0.2em] md:flex">
|
|
<a href="#homepage" onClick={(e) => scrollToSection(e, '#homepage')} className="hover:opacity-70 transition-opacity">Beranda</a>
|
|
<a href="#product" onClick={(e) => scrollToSection(e, '#product')} className="hover:opacity-70 transition-opacity">Produk</a>
|
|
<a href="#aboutUs" onClick={(e) => scrollToSection(e, '#aboutUs')} className="hover:opacity-70 transition-opacity">Tentang Kami</a>
|
|
</nav>
|
|
|
|
<div className="flex items-center gap-4">
|
|
<Link
|
|
href="/login"
|
|
className="hidden md:block border border-[#1e4a6d] px-6 py-2 text-[10px] font-bold uppercase tracking-widest transition-all hover:bg-[#1e4a6d] hover:text-white"
|
|
>
|
|
Masuk
|
|
</Link>
|
|
<button className="flex items-center gap-2 text-[10px] font-bold uppercase tracking-widest hover:opacity-70 md:hidden" onClick={() => setIsMenuOpen(!isMenuOpen)}>
|
|
<div className="flex flex-col gap-1">
|
|
<div className="h-[1px] w-5 bg-[#1e4a6d]"></div>
|
|
<div className="h-[1px] w-5 bg-[#1e4a6d]"></div>
|
|
<div className="h-[1px] w-5 bg-[#1e4a6d]"></div>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Hero Section */}
|
|
<section id="homepage" className="border-b border-[#1e4a6d]/20">
|
|
<div className="mx-auto max-w-7xl px-6 py-12 lg:px-12">
|
|
<div className="grid grid-cols-1 gap-12 lg:grid-cols-12 lg:items-center">
|
|
|
|
{/* Categories List */}
|
|
<div className="order-2 flex flex-col justify-center lg:order-1 lg:col-span-3">
|
|
<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}
|
|
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' : ''
|
|
}`}
|
|
>
|
|
{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'
|
|
}`} />
|
|
</button>
|
|
))}
|
|
{categories.length === 0 && (
|
|
<p className="py-8 text-center text-[10px] uppercase tracking-widest opacity-30 italic">Belum ada kategori</p>
|
|
)}
|
|
</div>
|
|
{/* Diagonal decorative lines like in the image */}
|
|
<div className="absolute -right-4 top-0 hidden h-full w-20 lg:block">
|
|
<div className="absolute h-full w-[1px] origin-top rotate-[15deg] bg-[#1e4a6d]/40"></div>
|
|
<div className="absolute right-0 h-full w-[1px] origin-top rotate-[15deg] bg-[#1e4a6d]/40"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="mt-8">
|
|
<p className="mb-4 text-[10px] font-bold uppercase tracking-widest opacity-60">Ikuti Kami</p>
|
|
<div className="flex gap-4">
|
|
<Facebook size={16} className="cursor-pointer hover:opacity-50" />
|
|
<X size={16} className="cursor-pointer hover:opacity-50" />
|
|
<Instagram size={16} className="cursor-pointer hover:opacity-50" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Hero Image */}
|
|
<div className="order-1 lg:order-2 lg:col-span-4">
|
|
<div className="relative aspect-[3/4] overflow-hidden bg-white shadow-xl">
|
|
<img src="https://images.unsplash.com/photo-1719947348984-b7af56dcdbfd?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDF8fHxlbnwwfHx8fHw%3D" alt="Model" className="h-full w-full object-cover" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Hero Text */}
|
|
<div className="order-3 lg:col-span-5">
|
|
<div className="max-w-md">
|
|
<h1 className="mb-6 text-4xl font-medium leading-[1.1] text-[#1e4a6d] lg:text-6xl">
|
|
Keahlian <br /> Yang Abadi
|
|
</h1>
|
|
<p className="mb-8 text-sm leading-relaxed opacity-70">
|
|
Tingkatkan gaya harian Anda dengan koleksi esensial yang dibuat dengan ketelitian dan kualitas tinggi. Mulai dari bahan berkelanjutan hingga desain yang tak lekang oleh waktu.
|
|
</p>
|
|
<a href="#product" onClick={(e) => scrollToSection(e, '#product')} className="inline-block bg-[#1e4a6d] px-8 py-3 text-[10px] font-bold uppercase tracking-[0.2em] text-white transition-all hover:bg-[#15344e]">
|
|
Jelajahi Sekarang
|
|
</a>
|
|
|
|
<div className="mt-16 flex gap-4">
|
|
{topSellingProducts.map((product, i) => (
|
|
<div
|
|
key={product.id}
|
|
className="group h-24 w-20 cursor-pointer overflow-hidden rounded-t-full border border-[#1e4a6d]/20 bg-white transition-all hover:scale-110"
|
|
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'}
|
|
alt={product.name}
|
|
className="h-full w-full object-cover"
|
|
/>
|
|
</div>
|
|
))}
|
|
{topSellingProducts.length === 0 && (
|
|
<div className="flex gap-4">
|
|
{[1, 2, 3].map(i => (
|
|
<div key={i} className="h-24 w-20 rounded-t-full border border-dashed border-[#1e4a6d]/20 bg-transparent"></div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Best Sellers Section */}
|
|
<section id="product" className="border-b border-[#1e4a6d]/20">
|
|
<div className="mx-auto max-w-7xl">
|
|
<div className="flex flex-col gap-4 border-x border-[#1e4a6d]/20 px-6 py-6 sm:flex-row sm:items-center sm:justify-between lg:px-12">
|
|
<h2 className="text-xl font-medium">Produk Terlaris</h2>
|
|
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
|
{/* Category Filter */}
|
|
<div className="relative">
|
|
<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"
|
|
>
|
|
<option value="">Semua Kategori</option>
|
|
{categories.map((cat: any) => (
|
|
<option key={cat.id} value={cat.slug}>{cat.name}</option>
|
|
))}
|
|
</select>
|
|
<div className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2">
|
|
<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..."
|
|
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]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Full-width borders wrapper */}
|
|
<div className="border-y border-[#1e4a6d]/20">
|
|
<div className="mx-auto max-w-7xl">
|
|
<div className="grid grid-cols-1 border-x border-[#1e4a6d]/20 sm:grid-cols-2 lg:grid-cols-4">
|
|
{allProducts.map((item, idx) => (
|
|
<div key={item.id} className="group border-b border-[#1e4a6d]/20 p-8 last:border-b-0 sm:border-r sm:even:border-r-0 lg:border-b-0 lg:border-r lg:last:border-r-0">
|
|
<div
|
|
className="mb-8 aspect-square overflow-hidden bg-white cursor-pointer"
|
|
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'}
|
|
alt={item.name}
|
|
className="h-full w-full object-cover transition-transform duration-500 group-hover:scale-110"
|
|
/>
|
|
</div>
|
|
<div className="text-center">
|
|
<div className="mb-2 flex flex-wrap justify-center gap-1">
|
|
{item.categories?.map((c: any) => (
|
|
<span key={c.id} className="rounded-full border border-[#1e4a6d]/10 bg-[#1e4a6d]/5 px-2 py-0.5 text-[7px] font-bold uppercase tracking-widest text-[#1e4a6d] opacity-60">
|
|
{c.name}
|
|
</span>
|
|
))}
|
|
</div>
|
|
<p className="mb-2 text-[10px] font-bold uppercase tracking-widest group-hover:text-indigo-600">
|
|
{item.name}
|
|
</p>
|
|
<p className="mb-4 text-sm font-medium opacity-60">{formatCurrency(item.retail_price)}</p>
|
|
|
|
<a
|
|
href={`https://wa.me/628123456789?text=${encodeURIComponent(`Halo ${setting?.site_name || 'VN Grup'}, saya ingin memesan ${item.name} seharga ${formatCurrency(item.retail_price)}. Mohon info detail pembayarannya.`)}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="inline-flex items-center gap-2 border border-[#1e4a6d] px-6 py-2 text-[8px] font-bold uppercase tracking-widest transition-all hover:bg-[#1e4a6d] hover:text-white"
|
|
>
|
|
Pesan Sekarang <ArrowRight size={10} />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
))}
|
|
{allProducts.length === 0 && (
|
|
<div className="col-span-full border-x border-[#1e4a6d]/20 py-32 text-center">
|
|
<div className="mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-[#1e4a6d]/5">
|
|
<Search size={24} className="opacity-20" />
|
|
</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
|
|
onClick={() => {
|
|
setSearch('');
|
|
setSelectedCategorySlug('');
|
|
}}
|
|
className="border border-[#1e4a6d] px-8 py-3 text-[10px] font-bold uppercase tracking-widest transition-all hover:bg-[#1e4a6d] hover:text-white"
|
|
>
|
|
Bersihkan Filter
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{bestSellers.next_page_url && (
|
|
<div className="border-t border-[#1e4a6d]/20 py-12 text-center border-x">
|
|
<button
|
|
onClick={loadMore}
|
|
className="group relative inline-flex items-center gap-4 border border-[#1e4a6d] px-12 py-4 text-[10px] font-bold uppercase tracking-[0.2em] transition-all hover:bg-[#1e4a6d] hover:text-white"
|
|
>
|
|
Muat Lebih Banyak
|
|
<ArrowRight size={14} className="transition-transform group-hover:translate-x-1" />
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Brand Section */}
|
|
<section id="aboutUs" className="border-b border-[#1e4a6d]/20 bg-[#f7f3eb]">
|
|
<div className="mx-auto max-w-7xl">
|
|
<div className="grid grid-cols-1 gap-20 border-x border-[#1e4a6d]/20 px-6 py-20 lg:grid-cols-2 lg:px-12">
|
|
<div className="flex flex-col justify-center">
|
|
<h2 className="mb-8 text-3xl font-medium">Tentang Kami</h2>
|
|
<p className="mb-6 text-sm leading-relaxed opacity-70">
|
|
Menghadirkan produk esensial untuk setiap momen berharga Anda. Dibuat dengan penuh perhatian, dirancang untuk bertahan lama. Menghargai kesederhanaan, mendefinisikan ulang gaya hidup.
|
|
</p>
|
|
<p className="mb-10 text-sm leading-relaxed opacity-70">
|
|
Keahlian tangan terbaik dalam setiap jahitan. Kain berkualitas yang memanjakan, daya tarik abadi sepanjang masa. Bagi mereka yang menghargai seni berpakaian yang sesungguhnya.
|
|
</p>
|
|
</div>
|
|
<div className="relative">
|
|
<div className="aspect-[4/3] overflow-hidden rounded-xl border border-[#1e4a6d]/20 shadow-2xl">
|
|
<img src="https://images.unsplash.com/photo-1615102731632-9978cdec7764?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDY3fHx8ZW58MHx8fHx8" alt="Brand" className="h-full w-full object-cover" />
|
|
</div>
|
|
{/* Decorative shirt at bottom right like in image */}
|
|
<div className="absolute -bottom-10 -right-4 h-32 w-32 rotate-12 overflow-hidden rounded-lg border border-[#1e4a6d]/20 shadow-xl lg:-left-10">
|
|
<img src="https://images.unsplash.com/photo-1733098033886-16454aef70a4?w=500&auto=format&fit=crop&q=60&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1yZWxhdGVkfDcwfHx8ZW58MHx8fHx8" alt="Shirt detail" className="h-full w-full object-cover" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Footer */}
|
|
<footer className="border-t border-[#1e4a6d]/20 bg-[#f7f3eb]">
|
|
<div className="mx-auto max-w-7xl border-x border-[#1e4a6d]/20">
|
|
<div className="grid grid-cols-1 gap-12 border-b border-[#1e4a6d]/10 px-6 py-16 lg:grid-cols-12 lg:px-12">
|
|
{/* Brand Info */}
|
|
<div className="lg:col-span-6">
|
|
<div className="mb-6 flex items-center gap-2 text-xl font-bold uppercase tracking-tighter">
|
|
{setting?.logo_light_url ? <img src={setting.logo_light_url} alt={setting.site_name} className="max-h-8" /> : (setting?.site_name || 'VN Grup')}
|
|
</div>
|
|
<p className="mb-8 text-sm leading-relaxed opacity-60">
|
|
{setting?.site_description || 'Menghadirkan produk esensial yang tak lekang oleh waktu dengan fokus pada kualitas, keberlanjutan, dan gaya yang abadi.'}
|
|
</p>
|
|
<div className="flex gap-4">
|
|
<Facebook size={18} className="cursor-pointer hover:opacity-50" />
|
|
<X size={18} className="cursor-pointer hover:opacity-50" />
|
|
<Instagram size={18} className="cursor-pointer hover:opacity-50" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Quick Links */}
|
|
<div className="lg:col-span-2">
|
|
<h3 className="mb-6 text-[10px] font-bold uppercase tracking-[0.2em]">Tautan</h3>
|
|
<ul className="flex flex-col gap-3 text-sm opacity-60">
|
|
<li><a href="#homepage" onClick={(e) => scrollToSection(e, '#homepage')} className="hover:underline cursor-pointer">Beranda</a></li>
|
|
<li><a href="#product" onClick={(e) => scrollToSection(e, '#product')} className="hover:underline cursor-pointer">Produk</a></li>
|
|
<li><a href="#aboutUs" onClick={(e) => scrollToSection(e, '#aboutUs')} className="hover:underline cursor-pointer">Tentang Kami</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
{/* Contact Info */}
|
|
<div className="lg:col-span-4">
|
|
<h3 className="mb-6 text-[10px] font-bold uppercase tracking-[0.2em]">Kontak</h3>
|
|
<div className="space-y-4 text-sm opacity-60">
|
|
<div className="flex gap-3">
|
|
<div className="shrink-0 pt-1">
|
|
<Search size={14} className="rotate-45" />
|
|
</div>
|
|
<p className="leading-relaxed whitespace-pre-line">
|
|
{setting?.site_address || 'Jl. Raya Utama No. 123, \n Kec. Lengkong, Kota Bandung, \n Jawa Barat 40262'}
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-3">
|
|
<Phone size={14} />
|
|
<a href={`https://wa.me/${(setting?.site_phone || '+628123456789').replace(/\D/g, '')}`} target="_blank" className="hover:underline">
|
|
{setting?.site_phone || '+62 812 3456 789'}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bottom Bar */}
|
|
<div className="px-6 py-6 text-center text-[10px] font-bold uppercase tracking-widest lg:px-12 lg:text-left">
|
|
<p className="opacity-50">© {new Date().getFullYear()} {setting?.site_name || 'VN Grup'}.</p>
|
|
</div>
|
|
</div>
|
|
</footer>
|
|
|
|
{/* Mobile Menu Overlay */}
|
|
{isMenuOpen && (
|
|
<div className="fixed inset-0 z-[60] flex flex-col items-center justify-center bg-[#f7f3eb] p-6 text-center animate-in fade-in slide-in-from-top-full duration-500">
|
|
<button className="absolute top-8 right-8 text-[#1e4a6d] transition-transform hover:rotate-90" onClick={() => setIsMenuOpen(false)}>
|
|
<X size={32} />
|
|
</button>
|
|
<div className="flex flex-col gap-8 text-3xl font-medium">
|
|
<a href="#homepage" onClick={(e) => scrollToSection(e, '#homepage')} className="hover:italic transition-all">Beranda</a>
|
|
<a href="#product" onClick={(e) => scrollToSection(e, '#product')} className="hover:italic transition-all">Produk</a>
|
|
<a href="#aboutUs" onClick={(e) => scrollToSection(e, '#aboutUs')} className="hover:italic transition-all">Tentang Kami</a>
|
|
<Link
|
|
href="/login"
|
|
className="mt-4 border border-[#1e4a6d] px-12 py-4 text-sm font-bold uppercase tracking-[0.2em] transition-all hover:bg-[#1e4a6d] hover:text-white"
|
|
>
|
|
Masuk
|
|
</Link>
|
|
</div>
|
|
<div className="mt-20 flex gap-6">
|
|
<Facebook size={24} className="hover:opacity-50 cursor-pointer" />
|
|
<X size={24} className="hover:opacity-50 cursor-pointer" />
|
|
<Instagram size={24} className="hover:opacity-50 cursor-pointer" />
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Product Detail Modal */}
|
|
<div className={`fixed inset-0 z-[70] flex items-center justify-center p-4 transition-all duration-500 ${selectedProduct ? 'visible opacity-100' : 'invisible opacity-0'
|
|
}`}>
|
|
<div className="absolute inset-0 bg-[#1e4a6d]/40 backdrop-blur-sm" onClick={() => setSelectedProduct(null)}></div>
|
|
<div className={`relative w-full max-w-4xl overflow-hidden bg-[#f7f3eb] shadow-2xl transition-all duration-500 ${selectedProduct ? 'translate-y-0 scale-100' : 'translate-y-10 scale-95'
|
|
}`}>
|
|
<button className="absolute right-4 top-4 z-10 p-2 hover:rotate-90 transition-transform" onClick={() => setSelectedProduct(null)}>
|
|
<X size={24} />
|
|
</button>
|
|
|
|
<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-[#fdfcf9]">
|
|
<div className="aspect-[4/5] overflow-hidden relative group/hero">
|
|
<img
|
|
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 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>
|
|
|
|
{/* 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 */}
|
|
<div className="flex flex-col p-8 md:p-12">
|
|
<div className="mb-6 flex flex-wrap gap-2">
|
|
{selectedProduct?.categories?.map((c: any) => (
|
|
<span key={c.id} className="rounded-full border border-[#1e4a6d]/20 bg-[#1e4a6d]/5 px-3 py-1 text-[8px] font-bold uppercase tracking-widest text-[#1e4a6d]">
|
|
{c.name}
|
|
</span>
|
|
))}
|
|
</div>
|
|
<h2 className="mb-4 text-3xl font-medium leading-tight">{selectedProduct?.name}</h2>
|
|
<p className="mb-8 text-2xl font-light text-[#1e4a6d]">{formatCurrency(selectedProduct?.retail_price || 0)}</p>
|
|
|
|
<div className="mb-10 space-y-4">
|
|
<p className="text-xs font-bold uppercase tracking-widest opacity-60">Deskripsi</p>
|
|
<p className="text-sm leading-relaxed opacity-70">
|
|
{selectedProduct?.description || 'Tidak ada deskripsi untuk produk ini.'}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mt-auto pt-8 border-t border-[#1e4a6d]/10">
|
|
<a
|
|
href={`https://wa.me/628123456789?text=${encodeURIComponent(`Halo ${setting?.site_name || 'VN Grup'}, saya tertarik dengan produk ${selectedProduct?.name} seharga ${formatCurrency(selectedProduct?.retail_price || 0)}. Bisa tanya-tanya dulu?`)}`}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="w-full bg-[#1e4a6d] py-4 text-[10px] font-bold uppercase tracking-[0.2em] text-white transition-all hover:bg-[#15344e] flex items-center justify-center gap-2"
|
|
>
|
|
Hubungi via WhatsApp <ArrowRight size={14} />
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|