- Implemented CartContext for managing cart state, including adding, removing, and updating items. - Added CartDrawer component to display cart items. - Updated AppHeader to include cart item count. - Enhanced welcome page with new layout, improved product image handling, and updated call-to-action buttons. - Refactored homepage data types to accommodate new features and removed unused properties.
653 lines
38 KiB
TypeScript
653 lines
38 KiB
TypeScript
import ProductCard from '@/components/home/ProductCard';
|
|
import CartDrawer from '@/components/home/CartDrawer';
|
|
import ProductModal from '@/components/home/ProductModal';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { useCart } from '@/contexts/cart-context';
|
|
import { formatRupiah } from '@/lib/rupiah';
|
|
import type { Category, HomepageData, Paginated, Product, ProductPrice } from '@/types/homepage';
|
|
import { Head, InfiniteScroll, Link, router } from '@inertiajs/react';
|
|
import {
|
|
ArrowRight,
|
|
Check,
|
|
ChevronRight,
|
|
Info,
|
|
LogIn,
|
|
Mail,
|
|
MapPin,
|
|
Phone,
|
|
Plus,
|
|
Search,
|
|
ShoppingBag,
|
|
Star,
|
|
} from 'lucide-react';
|
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
|
type Props = {
|
|
appName: string;
|
|
aboutApp: string | null;
|
|
contactEmail: string | null;
|
|
contactPhone: string | null;
|
|
contactAddress: string | null;
|
|
instagramUrl: string | null;
|
|
facebookUrl: string | null;
|
|
tiktokUrl: string | null;
|
|
homepage: HomepageData;
|
|
categories: Category[];
|
|
products: Paginated<Product>;
|
|
filters: { search: string; category: string };
|
|
seo: { title: string; description: string; image: string; url: string };
|
|
};
|
|
|
|
export default function Welcome({
|
|
appName,
|
|
aboutApp,
|
|
contactEmail,
|
|
contactPhone,
|
|
contactAddress,
|
|
instagramUrl,
|
|
facebookUrl,
|
|
tiktokUrl,
|
|
homepage,
|
|
categories,
|
|
products,
|
|
filters,
|
|
}: Props) {
|
|
const [searchInput, setSearchInput] = useState(filters.search);
|
|
const [selectedCategory, setSelectedCategory] = useState(filters.category);
|
|
const [activeProduct, setActiveProduct] = useState<Product | null>(null);
|
|
const [activeSection, setActiveSection] = useState('hero');
|
|
const [cartOpen, setCartOpen] = useState(false);
|
|
const searchTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);
|
|
const { totalItems } = useCart();
|
|
|
|
useEffect(() => {
|
|
const sections = ['hero', 'catalog', 'gallery', 'order-guide', 'about', 'contact'];
|
|
const observers: IntersectionObserver[] = [];
|
|
|
|
sections.forEach((id) => {
|
|
const el = document.getElementById(id);
|
|
if (!el) return;
|
|
|
|
const observer = new IntersectionObserver(
|
|
([entry]) => {
|
|
if (entry.isIntersecting) {
|
|
setActiveSection(id);
|
|
}
|
|
},
|
|
{ rootMargin: '-40% 0px -55% 0px' },
|
|
);
|
|
observer.observe(el);
|
|
observers.push(observer);
|
|
});
|
|
|
|
return () => observers.forEach((o) => o.disconnect());
|
|
}, []);
|
|
|
|
const FALLBACK_IMAGE = 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=800&auto=format&fit=crop&q=80';
|
|
|
|
const getProductImage = (product: Product): string => {
|
|
for (const variant of product.product_variants) {
|
|
if (variant.photo_urls && variant.photo_urls.length > 0) {
|
|
return variant.photo_urls[0];
|
|
}
|
|
}
|
|
return FALLBACK_IMAGE;
|
|
};
|
|
|
|
const getProductPriceRange = (product: Product): string => {
|
|
const prices = product.product_variants.flatMap((v) =>
|
|
v.product_prices
|
|
.filter((p: ProductPrice) => p.type === 'retail')
|
|
.map((p: ProductPrice) => p.price),
|
|
);
|
|
|
|
if (prices.length === 0) {
|
|
const fallbackPrices = product.product_variants.flatMap((v) =>
|
|
v.product_prices.map((p: ProductPrice) => p.price),
|
|
);
|
|
if (fallbackPrices.length === 0) return 'Rp 0';
|
|
const min = Math.min(...fallbackPrices);
|
|
const max = Math.max(...fallbackPrices);
|
|
return min === max ? `Rp ${formatRupiah(min)}` : `Rp ${formatRupiah(min)} - Rp ${formatRupiah(max)}`;
|
|
}
|
|
|
|
const min = Math.min(...prices);
|
|
const max = Math.max(...prices);
|
|
return min === max ? `Rp ${formatRupiah(min)}` : `Rp ${formatRupiah(min)} - Rp ${formatRupiah(max)}`;
|
|
};
|
|
|
|
const fetchProducts = useCallback(
|
|
(search: string, category: string) => {
|
|
const params = new URLSearchParams();
|
|
if (search) params.set('search', search);
|
|
if (category) params.set('category', category);
|
|
const url = `/${params.toString() ? `?${params.toString()}` : ''}`;
|
|
|
|
router.visit(url, {
|
|
only: ['products', 'filters'],
|
|
reset: ['products'],
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
});
|
|
},
|
|
[],
|
|
);
|
|
|
|
const handleSearchChange = useCallback(
|
|
(value: string) => {
|
|
setSearchInput(value);
|
|
if (searchTimeoutRef.current) {
|
|
clearTimeout(searchTimeoutRef.current);
|
|
}
|
|
searchTimeoutRef.current = setTimeout(() => {
|
|
fetchProducts(value, selectedCategory);
|
|
}, 400);
|
|
},
|
|
[selectedCategory, fetchProducts],
|
|
);
|
|
|
|
const handleCategoryChange = useCallback(
|
|
(slug: string | null) => {
|
|
const newCategory = slug ?? '';
|
|
setSelectedCategory(newCategory);
|
|
fetchProducts(searchInput, newCategory);
|
|
},
|
|
[searchInput, fetchProducts],
|
|
);
|
|
|
|
const handleResetFilters = useCallback(() => {
|
|
setSearchInput('');
|
|
setSelectedCategory('');
|
|
fetchProducts('', '');
|
|
}, [fetchProducts]);
|
|
|
|
const featuredProducts = products.data.slice(0, 3);
|
|
|
|
return (
|
|
<>
|
|
<Head title={appName}>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
|
</Head>
|
|
|
|
<div className="min-h-screen bg-gradient-to-tr from-amber-50/20 via-[#FDFDFC] to-yellow-50/30 text-slate-800 transition-colors duration-300 font-sans scroll-smooth">
|
|
{/* Sticky Header */}
|
|
<header className="sticky top-0 z-40 bg-white/70 backdrop-blur-lg border-b border-amber-100/50 transition-all">
|
|
<div className="max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
|
<Link href="/" className="flex items-center">
|
|
<img src="/assets/logo.png" alt={appName} className="h-12 w-auto" />
|
|
</Link>
|
|
|
|
<nav className="hidden lg:flex items-center space-x-8 text-xs font-semibold uppercase tracking-widest text-slate-600">
|
|
{[
|
|
{ id: 'hero', label: 'Beranda' },
|
|
{ id: 'catalog', label: 'Produk' },
|
|
{ id: 'about', label: 'Tentang Kami' },
|
|
{ id: 'order-guide', label: 'Cara Pesan' },
|
|
{ id: 'contact', label: 'Hubungi Kami' },
|
|
].map((item) => (
|
|
<a
|
|
key={item.id}
|
|
href={`#${item.id}`}
|
|
className={`transition-colors ${activeSection === item.id ? 'text-amber-600' : 'hover:text-amber-600'}`}
|
|
>
|
|
{item.label}
|
|
</a>
|
|
))}
|
|
</nav>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="ghost" size="icon" onClick={() => setCartOpen(true)} className="relative">
|
|
<ShoppingBag className="w-4.5 h-4.5 text-amber-600" />
|
|
{totalItems > 0 && (
|
|
<span className="absolute -top-1 -right-1 w-4.5 h-4.5 bg-amber-600 text-white text-[9px] font-bold rounded-full flex items-center justify-center">
|
|
{totalItems}
|
|
</span>
|
|
)}
|
|
</Button>
|
|
<Button variant="ghost" size="icon" asChild>
|
|
<a href="/admin/dashboard" aria-label="Login">
|
|
<LogIn className="w-4.5 h-4.5 text-amber-600" />
|
|
</a>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
{/* Hero Section */}
|
|
<section id="hero" className="relative min-h-[calc(100vh-80px)] flex flex-col justify-between overflow-hidden">
|
|
<div className="absolute inset-0 grid grid-cols-1 lg:grid-cols-2 pointer-events-none z-0">
|
|
<div className="bg-white/40/30" />
|
|
<div className="bg-gradient-to-tr from-amber-100/30 via-yellow-100/20 to-orange-50/30 border-l border-amber-100/20" />
|
|
</div>
|
|
|
|
<div className="max-w-7xl mx-auto px-6 w-full lg:grow grid grid-cols-1 lg:grid-cols-12 gap-8 items-center py-12 z-10">
|
|
{/* Left Column */}
|
|
<div className="lg:col-span-5 flex flex-col justify-center space-y-6 lg:pr-6">
|
|
<Badge variant="secondary" className="w-fit bg-amber-500/10 text-amber-700 uppercase tracking-widest font-bold px-3 py-1 shadow-sm">
|
|
Hadir dengan Gaya Terbaru
|
|
</Badge>
|
|
|
|
<h1 className="text-5xl md:text-6xl font-serif leading-[1.1] tracking-tight font-light select-none text-slate-800">
|
|
Nyaman<br />
|
|
dalam setiap{' '}
|
|
<span className="font-normal italic text-amber-600 bg-amber-100/20 px-2 rounded-lg">
|
|
Penampilan
|
|
</span>
|
|
</h1>
|
|
|
|
<p className="text-sm text-slate-500 max-w-md leading-relaxed font-light">
|
|
Koleksi fashion wanita dengan sentuhan elegan, material berkualitas, dan kenyamanan yang dapat Anda rasakan di setiap pemakaian.
|
|
</p>
|
|
|
|
<div className="flex items-center space-x-4 pt-4">
|
|
<Button asChild className="bg-amber-600 text-white px-8 py-3.5 text-xs font-semibold uppercase tracking-widest rounded-xl shadow-lg shadow-amber-200/50 hover:bg-amber-500 hover:-translate-y-0.5 transition-all duration-300 group">
|
|
<a href="#catalog">
|
|
Beli Sekarang
|
|
<ArrowRight className="w-3.5 h-3.5 ml-2 transform group-hover:translate-x-1 transition-transform" />
|
|
</a>
|
|
</Button>
|
|
<Button variant="outline" asChild className="border-amber-200 text-xs font-semibold uppercase tracking-widest px-8 py-3.5 rounded-xl hover:bg-amber-500/5 hover:border-amber-400 transition-all">
|
|
<a href="#about">Tentang Kami</a>
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Center Column: Visual */}
|
|
<div className="lg:col-span-7 relative flex justify-center items-center h-[500px] lg:h-[650px] w-full">
|
|
<div className="absolute inset-0 -z-10 flex justify-center items-center pointer-events-none select-none">
|
|
<div className="absolute w-[350px] h-[350px] rounded-full bg-gradient-to-tr from-amber-400/25 via-yellow-400/20 to-orange-300/20 blur-3xl" />
|
|
<div className="absolute w-[400px] h-[400px] rounded-full bg-gradient-to-br from-rose-300/20 via-amber-200/20 to-orange-300/20 blur-3xl" />
|
|
</div>
|
|
|
|
<div className="absolute inset-0 flex justify-center items-center pointer-events-none select-none z-0">
|
|
<div className="text-[14vw] lg:text-[120px] font-serif font-bold leading-none tracking-tight flex text-amber-200">
|
|
<span className="text-amber-600">DST</span>
|
|
<span className="text-slate-900">Collection</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="relative w-[310px] h-[440px] lg:w-[390px] lg:h-[540px] rounded-[2rem] overflow-hidden z-10 transition-transform duration-500 hover:scale-[1.02]">
|
|
<img
|
|
src={homepage.hero_image_url || 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=1000&auto=format&fit=crop&q=80'}
|
|
alt={appName}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
|
|
{/* Floating Tag 1 */}
|
|
{featuredProducts[0] && (
|
|
<div
|
|
onClick={() => setActiveProduct(featuredProducts[0])}
|
|
className="absolute top-10 left-4 md:-left-6 z-20 flex items-center space-x-3 bg-white/90 backdrop-blur-md p-3 rounded-2xl shadow-lg border border-amber-100/40 cursor-pointer transform hover:-translate-y-1 transition-all"
|
|
>
|
|
<img
|
|
src={getProductImage(featuredProducts[0])}
|
|
alt="Preview Produk"
|
|
className="w-10 h-10 object-cover rounded-lg"
|
|
/>
|
|
<div className="text-left">
|
|
<h4 className="text-[9px] font-bold text-amber-600 uppercase tracking-widest">Terpopuler</h4>
|
|
<p className="text-[11px] font-semibold truncate max-w-[100px]">{featuredProducts[0].name}</p>
|
|
<span className="text-[11px] font-bold text-amber-600">{getProductPriceRange(featuredProducts[0])}</span>
|
|
</div>
|
|
<div className="flex items-center justify-center w-6 h-6 rounded-full bg-amber-50/50 text-amber-600">
|
|
<Plus className="w-3.5 h-3.5" />
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Floating Tag 2 */}
|
|
{featuredProducts[1] && (
|
|
<div
|
|
onClick={() => setActiveProduct(featuredProducts[1])}
|
|
className="absolute top-28 right-4 md:-right-6 z-20 flex items-center space-x-3 bg-white/90 backdrop-blur-md p-3 rounded-2xl shadow-lg border border-amber-100/40 cursor-pointer transform hover:-translate-y-1 transition-all"
|
|
>
|
|
<img
|
|
src={getProductImage(featuredProducts[1])}
|
|
alt="Preview Produk"
|
|
className="w-10 h-10 object-cover rounded-lg"
|
|
/>
|
|
<div className="text-left">
|
|
<div className="flex items-center text-amber-400 space-x-0.5 mb-0.5">
|
|
{[1, 2, 3, 4, 5].map((i) => (
|
|
<Star key={i} className="w-2.5 h-2.5 fill-current" />
|
|
))}
|
|
</div>
|
|
<p className="text-[11px] font-semibold truncate max-w-[100px]">{featuredProducts[1].name}</p>
|
|
<span className="text-[10px] font-semibold text-emerald-500">Stok Tersedia</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Scroll Indicator */}
|
|
<div className="max-w-7xl mx-auto px-6 w-full flex items-center justify-between pb-8 z-10 text-xs font-semibold text-slate-500">
|
|
<div className="flex items-center space-x-3">
|
|
<span className="text-amber-600">#DSTCollection</span>
|
|
<span className="w-1 h-1 rounded-full bg-amber-300" />
|
|
<span>Bahan Adem & Lembut</span>
|
|
</div>
|
|
<Button
|
|
variant="ghost"
|
|
onClick={() => {
|
|
document.getElementById('catalog')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
}}
|
|
className="flex items-center space-x-2 hover:text-amber-600 transition-colors cursor-pointer text-xs font-semibold uppercase tracking-widest text-slate-500"
|
|
>
|
|
<span>Lihat katalog lengkap</span>
|
|
<ChevronRight className="w-3.5 h-3.5 rotate-90 text-amber-600" />
|
|
</Button>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Catalog Section */}
|
|
<section id="catalog" className="max-w-7xl mx-auto px-6 py-20 border-t border-amber-100/30">
|
|
<div className="space-y-6 mb-12">
|
|
<div className="text-center space-y-2">
|
|
<Badge variant="secondary" className="bg-amber-500/10 text-amber-700 uppercase tracking-[0.3em] font-bold px-3 py-1">
|
|
Katalog Eksklusif
|
|
</Badge>
|
|
<h3 className="text-3xl font-serif text-slate-800">Koleksi Busana Pilihan</h3>
|
|
<p className="text-sm text-slate-500 max-w-lg mx-auto font-light">Gunakan kategori dan filter di bawah untuk menyesuaikan pencarian busana idaman Anda dengan mudah.</p>
|
|
</div>
|
|
|
|
{/* Filters */}
|
|
<div className="bg-white/80 backdrop-blur-md p-6 rounded-3xl shadow-sm border border-amber-100/30 flex flex-col md:flex-row items-center gap-4 justify-between">
|
|
<div className="relative w-full md:w-80">
|
|
<Input
|
|
value={searchInput}
|
|
onChange={(e) => handleSearchChange(e.target.value)}
|
|
type="text"
|
|
placeholder="Cari produk..."
|
|
className="w-full bg-slate-50 border-slate-200 text-xs px-4 py-3 pr-10 rounded-xl focus:border-amber-500 text-slate-700 transition-all"
|
|
/>
|
|
<Search className="absolute right-3 top-3.5 w-4 h-4 text-slate-400" />
|
|
</div>
|
|
|
|
<div className="flex flex-wrap gap-2 w-full md:w-auto">
|
|
<Button
|
|
variant={!selectedCategory ? 'default' : 'outline'}
|
|
size="sm"
|
|
onClick={() => handleCategoryChange(null)}
|
|
className={`shrink-0 text-[11px] font-semibold uppercase tracking-wider rounded-xl transition-all whitespace-nowrap ${!selectedCategory
|
|
? 'bg-amber-600 text-white border-transparent shadow-md shadow-amber-200/50'
|
|
: 'bg-transparent text-slate-600 border-slate-200 hover'
|
|
}`}
|
|
>
|
|
Semua
|
|
</Button>
|
|
{categories.map((category) => (
|
|
<Button
|
|
key={category.id}
|
|
variant={selectedCategory === category.slug ? 'default' : 'outline'}
|
|
size="sm"
|
|
onClick={() => handleCategoryChange(selectedCategory === category.slug ? null : category.slug)}
|
|
className={`shrink-0 text-[11px] font-semibold uppercase tracking-wider rounded-xl transition-all whitespace-nowrap ${selectedCategory === category.slug
|
|
? 'bg-amber-600 text-white border-transparent shadow-md shadow-amber-200/50'
|
|
: 'bg-transparent text-slate-600 border-slate-200 hover'
|
|
}`}
|
|
>
|
|
{category.name}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Product Grid with Infinite Scroll */}
|
|
<InfiniteScroll
|
|
data="products"
|
|
onlyNext
|
|
buffer={300}
|
|
loading={() => (
|
|
<div className="col-span-full flex justify-center py-8">
|
|
<div className="flex items-center space-x-3 text-sm text-slate-400">
|
|
<div className="w-5 h-5 border-2 border-amber-400 border-t-transparent animate-spin rounded-full" />
|
|
<span>Memuat produk lainnya...</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
>
|
|
{products.data.length > 0 ? (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-x-8 gap-y-12">
|
|
{products.data.map((product) => (
|
|
<ProductCard
|
|
key={product.id}
|
|
product={product}
|
|
onQuickView={setActiveProduct}
|
|
contactPhone={contactPhone}
|
|
/>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="text-center py-20 space-y-3">
|
|
<Info className="w-12 h-12 text-amber-300 mx-auto" />
|
|
<h3 className="text-lg font-medium text-slate-700">Produk Tidak Ditemukan</h3>
|
|
<p className="text-sm text-slate-400">
|
|
Mohon maaf, kami tidak menemukan pakaian yang cocok dengan kata kunci pencarian Anda.
|
|
</p>
|
|
<Button variant="ghost" onClick={handleResetFilters} className="mt-2 text-xs font-bold uppercase tracking-widest text-amber-600 underline underline-offset-4">
|
|
Reset Pencarian
|
|
</Button>
|
|
</div>
|
|
)}
|
|
</InfiniteScroll>
|
|
</section>
|
|
|
|
{/* Gallery Section */}
|
|
<section id="gallery" className="w-full bg-gradient-to-br from-amber-50/40 via-yellow-50/20 to-orange-50/30 py-24 border-t border-b border-amber-100/30">
|
|
<div className="max-w-7xl mx-auto px-6 space-y-12">
|
|
<div className="text-center space-y-3 max-w-lg mx-auto">
|
|
<Badge variant="secondary" className="bg-amber-500/10 text-amber-700 uppercase tracking-[0.3em] font-bold px-3 py-1">
|
|
Galeri Kami
|
|
</Badge>
|
|
<h3 className="text-4xl font-serif leading-tight">Koleksi Lookbook</h3>
|
|
<p className="text-sm text-slate-500 leading-relaxed font-light">Intip koleksi lookbook kami untuk inspirasi gaya sehari-hari. Padu padan pakaian modern yang nyaman untuk berbagai suasana.</p>
|
|
</div>
|
|
|
|
{homepage.gallery_images.length > 0 ? (
|
|
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
|
|
{homepage.gallery_images.map((image, index) => (
|
|
<div
|
|
key={index}
|
|
className="group relative aspect-[3/4] rounded-2xl overflow-hidden shadow-md border-2 border-white cursor-pointer transition-all duration-300 hover:shadow-xl hover:-translate-y-1"
|
|
>
|
|
<img
|
|
src={image}
|
|
alt={`Lookbook ${index + 1}`}
|
|
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
|
|
/>
|
|
<div className="absolute inset-0 bg-gradient-to-t from-amber-950/40 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
|
|
</div>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="text-center py-12">
|
|
<p className="text-sm text-slate-400">Belum ada foto lookbook yang ditambahkan.</p>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</section>
|
|
|
|
{/* Order Guide Section */}
|
|
<section id="order-guide" className="max-w-7xl mx-auto px-6 py-20 border-b border-amber-100/30">
|
|
<div className="text-center space-y-3 mb-16">
|
|
<Badge variant="secondary" className="bg-amber-500/10 text-amber-700 uppercase tracking-[0.3em] font-bold px-3 py-1">
|
|
Langkah Pemesanan
|
|
</Badge>
|
|
<h4 className="text-3xl font-serif">Cara Melakukan Pemesanan</h4>
|
|
<p className="text-sm text-slate-500 max-w-md mx-auto font-light">Sistem pemesanan kami sangat mudah dan terhubung langsung via WhatsApp untuk pelayanan cepat dan personal.</p>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
|
|
{[
|
|
{ title: 'Pilih Produk', description: 'Jelajahi pakaian favorit Anda, lalu ketuk "Lihat Detail" untuk memeriksa varian.' },
|
|
{ title: 'Pilih Varian & Harga', description: 'Tentukan varian yang diinginkan dan pilih jenis harga (Eceran, Grosir, Agen, dll.).' },
|
|
{ title: 'Masukkan Keranjang', description: 'Masukkan ke Keranjang Belanja untuk menampung seluruh daftar pakaian yang ingin Anda beli.' },
|
|
{ title: 'Kirim ke WhatsApp', description: 'Klik tombol kirim pesanan, admin kami akan merespons rincian transfer bank dan pengiriman kurir.' },
|
|
].map((step, index) => (
|
|
<div
|
|
key={index}
|
|
className="bg-white/50 p-6 rounded-2xl border border-amber-100/30 shadow-sm relative overflow-hidden text-center group hover:-translate-y-1 transition-transform"
|
|
>
|
|
<div className="absolute -top-4 -right-4 w-16 h-16 bg-amber-100/50 rounded-full flex items-center justify-center text-amber-600 font-bold text-xl font-serif">
|
|
{index + 1}
|
|
</div>
|
|
<div className="w-12 h-12 rounded-xl bg-amber-100/30 text-amber-600 flex items-center justify-center mx-auto mb-4">
|
|
{index === 0 && <ShoppingBag className="w-5 h-5" />}
|
|
{index === 1 && <Star className="w-5 h-5" />}
|
|
{index === 2 && <Plus className="w-5 h-5" />}
|
|
{index === 3 && <Phone className="w-5 h-5" />}
|
|
</div>
|
|
<h5 className="font-bold text-base mb-2">{step.title}</h5>
|
|
<p className="text-xs text-slate-400 leading-relaxed font-light">{step.description}</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* About Section */}
|
|
<section id="about" className="max-w-7xl mx-auto px-6 py-20 border-b border-amber-100/30">
|
|
<div className="grid grid-cols-1 lg:grid-cols-12 gap-12 items-center">
|
|
<div className="lg:col-span-6 relative aspect-square max-w-md mx-auto lg:max-w-none rounded-3xl overflow-hidden shadow-lg border-2 border-white">
|
|
<img
|
|
src={homepage.about_image_url || 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80'}
|
|
alt="Tentang Kami"
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
<div className="lg:col-span-6 space-y-6">
|
|
<Badge variant="secondary" className="bg-amber-500/10 text-amber-700 uppercase tracking-[0.3em] font-bold px-3 py-1">
|
|
Tentang Kami
|
|
</Badge>
|
|
<h3 className="text-3xl font-serif">DST Collection</h3>
|
|
<p className="text-sm text-slate-500 leading-relaxed font-light whitespace-pre-line">
|
|
{aboutApp || 'Kami adalah rumah produksi busana lokal berkualitas tinggi. Berfokus pada keindahan motif, ketepatan detail jahitan, dan pemilihan kain adem yang mengedepankan aspek fungsionalitas dan estetika.'}
|
|
</p>
|
|
{['Kain Rayon Super Tebal & Menyerap Keringat', 'Motif Eksklusif & Tidak Pasaran', 'Dukungan Penuh Layanan Admin Via WhatsApp'].map((feature, index) => (
|
|
<div key={index} className="flex items-center space-x-3 text-xs text-slate-500 font-semibold">
|
|
<Check className="w-4 h-4 text-emerald-500" />
|
|
<span>{feature}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Contact Section */}
|
|
<section id="contact" className="max-w-7xl mx-auto px-6 py-20">
|
|
<div className="bg-white/60 backdrop-blur-md border border-amber-100/30 rounded-3xl overflow-hidden shadow-sm grid grid-cols-1 lg:grid-cols-2">
|
|
<div className="p-8 space-y-6 flex flex-col justify-center">
|
|
<Badge variant="secondary" className="bg-amber-500/10 text-amber-700 uppercase tracking-[0.3em] font-bold px-3 py-1 w-fit">
|
|
Kontak Kami
|
|
</Badge>
|
|
<h3 className="text-3xl font-serif">Ada Pertanyaan? Hubungi Kami</h3>
|
|
<p className="text-sm text-slate-500 leading-relaxed font-light">Kami sangat senang mendengarkan pertanyaan Anda terkait spesifikasi produk, ketersediaan grosir, atau kemitraan. Hubungi tim admin kami melalui media di bawah.</p>
|
|
|
|
<div className="space-y-3">
|
|
{contactPhone && (
|
|
<div className="flex items-center space-x-3 text-sm">
|
|
<div className="w-8 h-8 rounded-lg bg-amber-100/40 text-amber-600 flex items-center justify-center">
|
|
<Phone className="w-4 h-4" />
|
|
</div>
|
|
<span>{contactPhone}</span>
|
|
</div>
|
|
)}
|
|
{contactEmail && (
|
|
<div className="flex items-center space-x-3 text-sm">
|
|
<div className="w-8 h-8 rounded-lg bg-amber-100/40 text-amber-600 flex items-center justify-center">
|
|
<Mail className="w-4 h-4" />
|
|
</div>
|
|
<span>{contactEmail}</span>
|
|
</div>
|
|
)}
|
|
{contactAddress && (
|
|
<div className="flex items-center space-x-3 text-sm">
|
|
<div className="w-8 h-8 rounded-lg bg-amber-100/40 text-amber-600 flex items-center justify-center">
|
|
<MapPin className="w-4 h-4" />
|
|
</div>
|
|
<span>{contactAddress}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
<div className="h-80 lg:h-auto">
|
|
<iframe
|
|
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d304.913429094586!2d107.58352379265978!3d-6.414270414938328!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x2e696bd874fdab6d%3A0x12de5546c3d8eac4!2sAGEN%20JNE%20DEESTEPABUARAN!5e1!3m2!1sen!2sid!4v1786611903455!5m2!1sen!2sid"
|
|
width="100%"
|
|
height="100%"
|
|
style={{ border: 0 }}
|
|
allowFullScreen
|
|
loading="lazy"
|
|
referrerPolicy="no-referrer-when-downgrade"
|
|
className="w-full h-full min-h-[320px]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
{/* Footer */}
|
|
<footer className="bg-white text-slate-600 py-16 border-t border-amber-100/30">
|
|
<div className="max-w-7xl mx-auto px-6 grid grid-cols-1 md:grid-cols-4 gap-8">
|
|
<div className="space-y-4">
|
|
<img src="/assets/logo.png" alt={appName} className="h-10 w-auto" />
|
|
<p className="text-xs text-slate-400 leading-relaxed font-light">
|
|
Galeri resmi {appName}. Pilihan busana lokal premium berpotongan modern dengan kenyamanan menyejukkan.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<h4 className="text-xs uppercase font-bold text-slate-800 tracking-widest">Koleksi Kami</h4>
|
|
<ul className="space-y-2 text-xs">
|
|
{categories.slice(0, 4).map((cat) => (
|
|
<li key={cat.id}>
|
|
<a href="#catalog" className="hover transition-colors">{cat.name}</a>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<h4 className="text-xs uppercase font-bold text-slate-800 tracking-widest">Tautan</h4>
|
|
<ul className="space-y-2 text-xs">
|
|
<li><a href="#about" className="hover transition-colors">Tentang Kami</a></li>
|
|
<li><a href="#order-guide" className="hover transition-colors">Cara Pemesanan</a></li>
|
|
<li><a href="#contact" className="hover transition-colors">Hubungi Kami</a></li>
|
|
<li><a href="/admin/dashboard" className="hover transition-colors font-semibold">Login Dashboard Admin</a></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<h4 className="text-xs uppercase font-bold text-slate-800 tracking-widest">Sosial Media</h4>
|
|
<p className="text-xs text-slate-400 font-light">Ikuti sosial media kami untuk mendapatkan update produk terbaru.</p>
|
|
<div className="flex space-x-3 text-xs">
|
|
{instagramUrl && (
|
|
<a href={instagramUrl} target="_blank" rel="noreferrer" className="text-slate-400 hover">Instagram</a>
|
|
)}
|
|
{facebookUrl && (
|
|
<a href={facebookUrl} target="_blank" rel="noreferrer" className="text-slate-400 hover">Facebook</a>
|
|
)}
|
|
{tiktokUrl && (
|
|
<a href={tiktokUrl} target="_blank" rel="noreferrer" className="text-slate-400 hover">TikTok</a>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="max-w-7xl mx-auto px-6 mt-12 pt-8 border-t border-amber-100/30 flex flex-col sm:flex-row justify-between items-center text-[10px] text-slate-400 font-light space-y-4 sm:space-y-0">
|
|
<p>© {new Date().getFullYear()} {appName}. Hak Cipta Dilindungi.</p>
|
|
</div>
|
|
</footer>
|
|
|
|
{/* Product Modal */}
|
|
<ProductModal product={activeProduct} onClose={() => setActiveProduct(null)} contactPhone={contactPhone} />
|
|
<CartDrawer open={cartOpen} onClose={() => setCartOpen(false)} contactPhone={contactPhone} />
|
|
</div>
|
|
</>
|
|
);
|
|
}
|