diff --git a/app/Http/Controllers/HomepageController.php b/app/Http/Controllers/HomepageController.php index 71933c8..234b332 100644 --- a/app/Http/Controllers/HomepageController.php +++ b/app/Http/Controllers/HomepageController.php @@ -38,6 +38,7 @@ public function __invoke(Request $request): Response 'categories:id,name,slug', 'productVariants:id,product_id,name,stock', 'productVariants.productPrices:id,variant_id,type,price', + 'productVariants.media', ]); if ($search !== '') { @@ -53,9 +54,23 @@ public function __invoke(Request $request): Response }); } - $products = Inertia::scroll( - fn () => $productsQuery->orderBy('created_at', 'desc')->paginate(12) - ); + $s3Service = $this->s3Service; + $products = Inertia::scroll(function () use ($productsQuery, $s3Service) { + $paginator = $productsQuery->orderBy('created_at', 'desc')->paginate(12); + + $paginator->getCollection()->each(function ($product) use ($s3Service) { + $product->productVariants->each(function ($variant) use ($s3Service) { + $media = $variant->getMedia('images'); + $variant->photo_urls = $media->map( + fn ($m) => str_starts_with($m->getPath(), 'http') + ? $m->getPath() + : $s3Service->getTemporaryUrl($m->getPath(), 60) + )->toArray(); + }); + }); + + return $paginator; + }); $galleryImages = array_map( fn ($key) => str_starts_with($key, 'http') ? $key : $this->s3Service->getTemporaryUrl($key, 60), @@ -72,44 +87,13 @@ public function __invoke(Request $request): Response 'facebookUrl' => $socialMedia->facebook_url, 'tiktokUrl' => $socialMedia->tiktok_url, 'homepage' => [ - 'hero_badge' => $homepage->hero_badge, - 'hero_title_line1' => $homepage->hero_title_line1, - 'hero_title_line2' => $homepage->hero_title_line2, - 'hero_title_highlight' => $homepage->hero_title_highlight, - 'hero_description' => $homepage->hero_description, - 'hero_cta_primary_text' => $homepage->hero_cta_primary_text, - 'hero_cta_secondary_text' => $homepage->hero_cta_secondary_text, 'hero_image_url' => $homepage->hero_image_url ? (str_starts_with($homepage->hero_image_url, 'http') ? $homepage->hero_image_url : $this->s3Service->getTemporaryUrl($homepage->hero_image_url, 60)) : null, - 'hero_bg_text_left' => $homepage->hero_bg_text_left, - 'hero_bg_text_right' => $homepage->hero_bg_text_right, - 'scroll_hashtag' => $homepage->scroll_hashtag, - 'scroll_tagline' => $homepage->scroll_tagline, - 'catalog_badge' => $homepage->catalog_badge, - 'catalog_title' => $homepage->catalog_title, - 'catalog_description' => $homepage->catalog_description, - 'catalog_search_placeholder' => $homepage->catalog_search_placeholder, - 'gallery_badge' => $homepage->gallery_badge, - 'gallery_title' => $homepage->gallery_title, - 'gallery_description' => $homepage->gallery_description, - 'gallery_images' => $galleryImages, - 'order_guide_badge' => $homepage->order_guide_badge, - 'order_guide_title' => $homepage->order_guide_title, - 'order_guide_description' => $homepage->order_guide_description, - 'order_steps' => $homepage->order_steps, - 'about_badge' => $homepage->about_badge, - 'about_title' => $homepage->about_title, 'about_image_url' => $homepage->about_image_url ? (str_starts_with($homepage->about_image_url, 'http') ? $homepage->about_image_url : $this->s3Service->getTemporaryUrl($homepage->about_image_url, 60)) : null, - 'about_features' => $homepage->about_features, - 'contact_badge' => $homepage->contact_badge, - 'contact_title' => $homepage->contact_title, - 'contact_description' => $homepage->contact_description, - 'contact_form_title' => $homepage->contact_form_title, - 'footer_description' => $homepage->footer_description, - 'footer_copyright' => $homepage->footer_copyright, + 'gallery_images' => $galleryImages, ], 'categories' => $categories, 'products' => $products, @@ -118,8 +102,8 @@ public function __invoke(Request $request): Response 'category' => $category, ], 'seo' => [ - 'title' => $system->app_name.' - '.$homepage->hero_badge, - 'description' => $homepage->hero_description, + 'title' => $system->app_name.' - Koleksi Segar 2026', + 'description' => 'Selamat datang di '.$system->app_name.'. Temukan keanggunan motif batik modern dan setelan pakaian santai berkualitas premium.', 'image' => url('/assets/logo.png'), 'url' => url('/'), ], diff --git a/app/Settings/HomepageSettings.php b/app/Settings/HomepageSettings.php index d851f7c..3aea90f 100644 --- a/app/Settings/HomepageSettings.php +++ b/app/Settings/HomepageSettings.php @@ -6,73 +6,11 @@ class HomepageSettings extends Settings { - public string $hero_badge; - - public string $hero_title_line1; - - public string $hero_title_line2; - - public string $hero_title_highlight; - - public string $hero_description; - - public string $hero_cta_primary_text; - - public string $hero_cta_secondary_text; - public ?string $hero_image_url; - public string $hero_bg_text_left; - - public string $hero_bg_text_right; - - public string $scroll_hashtag; - - public string $scroll_tagline; - - public string $catalog_badge; - - public string $catalog_title; - - public string $catalog_description; - - public string $catalog_search_placeholder; - - public string $gallery_badge; - - public string $gallery_title; - - public string $gallery_description; - - public array $gallery_images; - - public string $order_guide_badge; - - public string $order_guide_title; - - public string $order_guide_description; - - public array $order_steps; - - public string $about_badge; - - public string $about_title; - public ?string $about_image_url; - public array $about_features; - - public string $contact_badge; - - public string $contact_title; - - public string $contact_description; - - public string $contact_form_title; - - public string $footer_description; - - public string $footer_copyright; + public array $gallery_images; public static function group(): string { diff --git a/database/settings/2026_06_20_110000_create_homepage_settings.php b/database/settings/2026_06_20_110000_create_homepage_settings.php index 13cc1a1..2141360 100644 --- a/database/settings/2026_06_20_110000_create_homepage_settings.php +++ b/database/settings/2026_06_20_110000_create_homepage_settings.php @@ -8,82 +8,16 @@ public function up(): void { $this->migrator->inGroup('homepage', function (SettingsBlueprint $blueprint): void { - // Hero Section - $blueprint->add('hero_badge', 'Koleksi Segar 2026'); - $blueprint->add('hero_title_line1', 'Ekspresikan'); - $blueprint->add('hero_title_line2', 'Gaya'); - $blueprint->add('hero_title_highlight', 'Segar Anda'); - $blueprint->add('hero_description', 'Selamat datang di {app_name}. Temukan keanggunan motif batik modern dan setelan pakaian santai berkualitas premium. Dirancang khusus dengan bahan adem yang menyejukkan aktivitas harian Anda.'); - $blueprint->add('hero_cta_primary_text', 'Beli Sekarang'); - $blueprint->add('hero_cta_secondary_text', 'Tentang Kami'); $blueprint->add('hero_image_url', 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=1000&auto=format&fit=crop&q=80'); - $blueprint->add('hero_bg_text_left', 'DST'); - $blueprint->add('hero_bg_text_right', 'Collection'); - - // Scroll Indicator - $blueprint->add('scroll_hashtag', '#DSTCollection'); - $blueprint->add('scroll_tagline', 'Bahan Adem & Lembut'); - - // Catalog Section - $blueprint->add('catalog_badge', 'Katalog Eksklusif'); - $blueprint->add('catalog_title', 'Koleksi Busana Pilihan'); - $blueprint->add('catalog_description', 'Gunakan kategori dan filter di bawah untuk menyesuaikan pencarian busana idaman Anda dengan mudah.'); - $blueprint->add('catalog_search_placeholder', 'Cari nama pakaian...'); - - // Deal Section - $blueprint->add('deal_badge', 'Promo Terbatas'); - $blueprint->add('deal_title', 'Penawaran Bulan Ini'); - $blueprint->add('deal_description', 'Jangan lewatkan promosi batik dan daster eksklusif kami! Dapatkan potongan harga spesial up to 25% untuk varian daster pilihan dan setelan pakaian modern. Dapatkan kenyamanan ekstra dengan bahan menyejukkan sebelum masa promo habis!'); - $blueprint->add('deal_cta_text', 'Jelajahi Produk Diskon'); - $blueprint->add('deal_images', [ + $blueprint->add('about_image_url', 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80'); + $blueprint->add('gallery_images', [ 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80', 'https://images.unsplash.com/photo-1572804013309-59a88b7e92f1?w=800&auto=format&fit=crop&q=80', 'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800&auto=format&fit=crop&q=80', 'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=800&auto=format&fit=crop&q=80', + 'https://images.unsplash.com/photo-1496747611176-843222e1e57c?w=800&auto=format&fit=crop&q=80', + 'https://images.unsplash.com/photo-1509631179647-0177331693ae?w=800&auto=format&fit=crop&q=80', ]); - - // Order Guide Section - $blueprint->add('order_guide_badge', 'Langkah Pemesanan'); - $blueprint->add('order_guide_title', 'Cara Melakukan Pemesanan'); - $blueprint->add('order_guide_description', 'Sistem pemesanan kami sangat mudah dan terhubung langsung via WhatsApp untuk pelayanan cepat dan personal.'); - $blueprint->add('order_steps', [ - [ - 'title' => 'Pilih Produk', - 'description' => 'Jelajahi pakaian batik dan daster favorit Anda, lalu ketuk "Lihat Detail" untuk memeriksa ukuran.', - ], - [ - 'title' => 'Pilih Varian & Harga', - 'description' => 'Tentukan varian ukuran 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.', - ], - ]); - - // About Section - $blueprint->add('about_badge', 'Tentang Kami'); - $blueprint->add('about_title', 'DST Collection'); - $blueprint->add('about_image_url', 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80'); - $blueprint->add('about_features', [ - 'Kain Rayon Super Tebal & Menyerap Keringat', - 'Motif Eksklusif & Tidak Pasaran', - 'Dukungan Penuh Layanan Admin Via WhatsApp', - ]); - - // Contact Section - $blueprint->add('contact_badge', 'Kontak Kami'); - $blueprint->add('contact_title', 'Ada Pertanyaan? Hubungi Kami'); - $blueprint->add('contact_description', 'Kami sangat senang mendengarkan pertanyaan Anda terkait spesifikasi produk, ketersediaan grosir, atau kemitraan. Hubungi tim admin kami melalui media di bawah.'); - $blueprint->add('contact_form_title', 'Kirim Pesan Cepat'); - - // Footer - $blueprint->add('footer_description', 'Galeri resmi {app_name}. Pilihan busana lokal premium berpotongan modern dengan kenyamanan menyejukkan.'); - $blueprint->add('footer_copyright', '© 2026 {app_name} DST Collection. Hak Cipta Dilindungi.'); }); } }; diff --git a/database/settings/2026_06_20_120000_rename_deal_to_gallery_in_homepage.php b/database/settings/2026_06_20_120000_rename_deal_to_gallery_in_homepage.php index 29eeac2..e9fa72c 100644 --- a/database/settings/2026_06_20_120000_rename_deal_to_gallery_in_homepage.php +++ b/database/settings/2026_06_20_120000_rename_deal_to_gallery_in_homepage.php @@ -8,25 +8,11 @@ public function up(): void { $this->migrator->inGroup('homepage', function (SettingsBlueprint $blueprint): void { - // Delete old deal fields $blueprint->delete('deal_badge'); $blueprint->delete('deal_title'); $blueprint->delete('deal_description'); $blueprint->delete('deal_cta_text'); $blueprint->delete('deal_images'); - - // Add new gallery fields - $blueprint->add('gallery_badge', 'Galeri Kami'); - $blueprint->add('gallery_title', 'Koleksi Lookbook'); - $blueprint->add('gallery_description', 'Intip koleksi lookbook kami untuk inspirasi gaya sehari-hari. Padu padan batik modern dan daster yang nyaman untuk berbagai suasana.'); - $blueprint->add('gallery_images', [ - 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1572804013309-59a88b7e92f1?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1496747611176-843222e1e57c?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1509631179647-0177331693ae?w=800&auto=format&fit=crop&q=80', - ]); }); } }; diff --git a/resources/js/app.tsx b/resources/js/app.tsx index 5721e83..2ae9f15 100644 --- a/resources/js/app.tsx +++ b/resources/js/app.tsx @@ -1,6 +1,7 @@ import { FlashToast, PWAUpdateToast } from '@/components/notifications'; import { Toaster } from '@/components/ui/sonner'; import { TooltipProvider } from '@/components/ui/tooltip'; +import { CartProvider } from '@/contexts/cart-context'; import { initializeTheme } from '@/hooks/use-appearance'; import AppLayout from '@/layouts/app-layout'; import AuthLayout from '@/layouts/auth-layout'; @@ -38,12 +39,14 @@ createInertiaApp({ strictMode: true, withApp(app) { return ( - - - - {app} - - + + + + + {app} + + + ); }, progress: { diff --git a/resources/js/components/home/CartDrawer.tsx b/resources/js/components/home/CartDrawer.tsx new file mode 100644 index 0000000..e876b15 --- /dev/null +++ b/resources/js/components/home/CartDrawer.tsx @@ -0,0 +1,113 @@ +import { Button } from '@/components/ui/button'; +import { useCart } from '@/contexts/cart-context'; +import { formatRupiah } from '@/lib/rupiah'; +import { formatWhatsAppPhone } from '@/lib/format'; +import { Minus, Plus, ShoppingBag, ShoppingCart, Trash2, X } from 'lucide-react'; + +type CartDrawerProps = { + open: boolean; + onClose: () => void; + contactPhone?: string | null; +}; + +export default function CartDrawer({ open, onClose, contactPhone }: CartDrawerProps) { + const { items, removeItem, updateQuantity, clearCart, totalItems, totalPrice } = useCart(); + + if (!open) return null; + + const handleCheckout = () => { + if (items.length === 0 || !contactPhone) return; + + const lines = items.map((item) => { + const subtotal = item.price * item.quantity; + return `*${item.productName}*\n* Varian: ${item.variantName}\n* Harga: Rp ${formatRupiah(item.price)}\n* QTY : ${item.quantity}\n* Subtotal : Rp ${formatRupiah(subtotal)}`; + }); + const message = `Halo min, saya mau order, berikut pesanannya.\n\n${lines.join('\n\n')}\n\nTotal: Rp ${formatRupiah(totalPrice)}\n\nMohon diinformasikan detail pembayaran dan proses selanjutnya ya, Kak.\n\nTerimakasih`; + const waUrl = `https://wa.me/${formatWhatsAppPhone(contactPhone || '')}?text=${encodeURIComponent(message)}`; + window.open(waUrl, '_blank'); + }; + + return ( +
+
+
e.stopPropagation()} + > + {/* Header */} +
+
+ +

Keranjang

+ ({totalItems} item) +
+
+ {items.length > 0 && ( + + )} + +
+
+ + {/* Items */} +
+ {items.length === 0 ? ( +
+ +

Keranjang kosong

+

Tambahkan produk untuk mulai berbelanja

+
+ ) : ( + items.map((item) => ( +
+
+ {item.productName} +
+
+

{item.productName}

+

{item.variantName} · {item.priceType === 'retail' ? 'Retail' : 'Grosir'}

+

Rp {formatRupiah(item.price)}

+
+
+ + {item.quantity} + +
+ +
+
+
+ )) + )} +
+ + {/* Footer */} + {items.length > 0 && ( +
+
+ Total + Rp {formatRupiah(totalPrice)} +
+ +
+ )} +
+
+ ); +} diff --git a/resources/js/components/home/ProductCard.tsx b/resources/js/components/home/ProductCard.tsx index 1130413..b3c0cdc 100644 --- a/resources/js/components/home/ProductCard.tsx +++ b/resources/js/components/home/ProductCard.tsx @@ -1,42 +1,27 @@ +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { useCart } from '@/contexts/cart-context'; import { formatRupiah } from '@/lib/rupiah'; +import { formatWhatsAppPhone } from '@/lib/format'; import type { Product } from '@/types/homepage'; +import { ShoppingBag, ShoppingCart } from 'lucide-react'; +import { toast } from 'sonner'; type ProductCardProps = { product: Product; onQuickView: (product: Product) => void; + contactPhone?: string | null; }; +const FALLBACK_IMAGE = 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=800&auto=format&fit=crop&q=80'; + function getProductImage(product: Product): string { for (const variant of product.product_variants) { - const prices = variant.product_prices; - if (prices.length > 0) { - return `https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=800&auto=format&fit=crop&q=80`; + if (variant.photo_urls && variant.photo_urls.length > 0) { + return variant.photo_urls[0]; } } - - const fallbacks: Record = { - 'daster': [ - 'https://images.unsplash.com/photo-1595777457583-95e059d581b8?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1572804013309-59a88b7e92f1?w=800&auto=format&fit=crop&q=80', - ], - 'setelan-celana': [ - 'https://images.unsplash.com/photo-1539109136881-3be0616acf4b?w=800&auto=format&fit=crop&q=80', - ], - 'atasan': [ - 'https://images.unsplash.com/photo-1515886657613-9f3515b0c78f?w=800&auto=format&fit=crop&q=80', - ], - 'bawahan': [ - 'https://images.unsplash.com/photo-1583496661160-fb4886b36ca7?w=800&auto=format&fit=crop&q=80', - ], - }; - - const firstCat = product.categories?.[0]?.slug || ''; - const categoryUrls = fallbacks[firstCat] || [ - 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=800&auto=format&fit=crop&q=80', - 'https://images.unsplash.com/photo-1434389677669-e08b4cac3105?w=800&auto=format&fit=crop&q=80', - ]; - - return categoryUrls[0]; + return FALLBACK_IMAGE; } function getProductPriceRange(product: Product): string { @@ -71,46 +56,87 @@ function getProductPriceRange(product: Product): string { : `Rp ${formatRupiah(min)} - Rp ${formatRupiah(max)}`; } -export default function ProductCard({ product, onQuickView }: ProductCardProps) { +export default function ProductCard({ product, onQuickView, contactPhone }: ProductCardProps) { + const { addItem } = useCart(); + + console.log(contactPhone) + + const handleAddToCart = () => { + const variant = product.product_variants[0]; + if (!variant) return; + + const retail = variant.product_prices.find((p) => p.type === 'retail'); + const wholesale = variant.product_prices.find((p) => p.type === 'wholesale'); + const price = retail?.price ?? wholesale?.price ?? 0; + + addItem({ + productId: product.id, + productName: product.name, + variantId: variant.id, + variantName: variant.name, + priceType: 'retail', + price, + imageUrl: getProductImage(product), + }); + toast.success(`${product.name} ditambahkan ke keranjang`); + }; + + const variant = product.product_variants[0]; + const retail = variant?.product_prices.find((p) => p.type === 'retail'); + const price = retail?.price ?? 0; + const waMessage = encodeURIComponent( + `Halo min, saya mau order, berikut pesanannya.\n\n*${product.name}*\n* Varian: ${variant?.name ?? '-'}\n* Harga: Rp ${formatRupiah(price)}\n* QTY : 1\n* Subtotal : Rp ${formatRupiah(price)}\n\nTotal: Rp ${formatRupiah(price)}\n\nMohon diinformasikan detail pembayaran dan proses selanjutnya ya, Kak.\n\nTerimakasih` + ); + const waUrl = `https://wa.me/${formatWhatsAppPhone(contactPhone || '')}?text=${waMessage}`; + return ( -
onQuickView(product)} - > +
onQuickView(product)}>
{product.name} -
-
- - Lihat Detail - -
-
+
{product.categories.slice(0, 2).map((cat) => ( - + {cat.name} - + ))}

{product.name}

-

- {product.description || 'Koleksi fashion berkualitas'} -

{getProductPriceRange(product)}

+
+ + +
); diff --git a/resources/js/components/home/ProductModal.tsx b/resources/js/components/home/ProductModal.tsx index 59f22bd..3e8d90a 100644 --- a/resources/js/components/home/ProductModal.tsx +++ b/resources/js/components/home/ProductModal.tsx @@ -1,15 +1,26 @@ -import { X, Star, Minus, Plus, Phone } from 'lucide-react'; -import { useState } from 'react'; +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { useCart } from '@/contexts/cart-context'; import { formatRupiah } from '@/lib/rupiah'; -import type { Product, ProductVariant, ProductPrice } from '@/types/homepage'; +import { formatWhatsAppPhone } from '@/lib/format'; +import type { Product, ProductVariant } from '@/types/homepage'; +import { Minus, Plus, ShoppingBag, ShoppingCart, X } from 'lucide-react'; +import { useState } from 'react'; +import { toast } from 'sonner'; type ProductModalProps = { product: Product | null; onClose: () => void; + contactPhone?: string | null; }; -function getProductImage(): string { - return 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=1000&auto=format&fit=crop&q=80'; +const FALLBACK_IMAGE = 'https://images.unsplash.com/photo-1490481651871-ab68de25d43d?w=1000&auto=format&fit=crop&q=80'; + +function getVariantImage(variant: ProductVariant): string { + if (variant.photo_urls && variant.photo_urls.length > 0) { + return variant.photo_urls[0]; + } + return FALLBACK_IMAGE; } function getRetailPrice(variant: ProductVariant): number { @@ -22,29 +33,46 @@ function getWholesalePrice(variant: ProductVariant): number { return wholesale?.price ?? 0; } -export default function ProductModal({ product, onClose }: ProductModalProps) { +export default function ProductModal({ product, onClose, contactPhone }: ProductModalProps) { const [selectedVariant, setSelectedVariant] = useState(null); const [selectedPriceType, setSelectedPriceType] = useState<'retail' | 'wholesale'>('retail'); + const [selectedImage, setSelectedImage] = useState(null); const [quantity, setQuantity] = useState(1); + const { addItem } = useCart(); if (!product) return null; const variants = product.product_variants; const activeVariant = selectedVariant ?? variants[0]; + const variantImages: string[] = activeVariant?.photo_urls?.length + ? activeVariant.photo_urls + : [FALLBACK_IMAGE]; + const currentImage = selectedImage ?? variantImages[0]; const retailPrice = activeVariant ? getRetailPrice(activeVariant) : 0; const wholesalePrice = activeVariant ? getWholesalePrice(activeVariant) : 0; const currentPrice = selectedPriceType === 'retail' ? retailPrice : wholesalePrice; const maxStock = activeVariant?.stock ?? 0; - const handleWhatsAppOrder = () => { + const handleVariantChange = (variant: ProductVariant) => { + setSelectedVariant(variant); + setSelectedImage(null); + setQuantity(1); + }; + + const handleAddToCart = () => { if (!activeVariant) return; - const priceLabel = selectedPriceType === 'retail' ? 'Retail' : 'Grosir'; - const message = `Halo, saya tertarik dengan produk:\n\n*${product.name}*\n- Varian: ${activeVariant.name}\n- Harga ${priceLabel}: Rp ${formatRupiah(currentPrice)}\n- Jumlah: ${quantity} pcs\n- Subtotal: Rp ${formatRupiah(currentPrice * quantity)}\n\nMohon info detail pesanan. Terima kasih!`; - - const phone = '6281234567890'; - const waUrl = `https://wa.me/${phone}?text=${encodeURIComponent(message)}`; - window.open(waUrl, '_blank'); + addItem({ + productId: product.id, + productName: product.name, + variantId: activeVariant.id, + variantName: activeVariant.name, + priceType: selectedPriceType, + price: currentPrice, + imageUrl: getVariantImage(activeVariant), + quantity, + }); + toast.success(`${product.name} ditambahkan ke keranjang`); }; return ( @@ -59,22 +87,43 @@ export default function ProductModal({ product, onClose }: ProductModalProps) { {/* Header */}

Detail Produk

- +
{/* Image */} -
- {product.name} +
+
+ {product.name} +
+ + {variantImages.length > 1 && ( +
+ {variantImages.map((url, i) => ( + + ))} +
+ )}
{/* Details */} @@ -82,12 +131,9 @@ export default function ProductModal({ product, onClose }: ProductModalProps) {
{product.categories.slice(0, 2).map((cat) => ( - + {cat.name} - + ))}

{product.name}

@@ -97,29 +143,12 @@ export default function ProductModal({ product, onClose }: ProductModalProps) { {product.description || 'Produk fashion berkualitas dengan desain elegan dan bahan nyaman.'}

- {/* Rating */} -
-
- - - - - -
- 5.0 (120+) -
- {/* Price */}

Harga

Rp {formatRupiah(currentPrice)}

- {selectedPriceType === 'wholesale' && wholesalePrice > 0 && ( -

- Harga retail: Rp {formatRupiah(retailPrice)} -

- )}
{/* Variant Selection */} @@ -128,20 +157,21 @@ export default function ProductModal({ product, onClose }: ProductModalProps) {

Varian

{variants.map((variant) => ( - + ))}
@@ -151,26 +181,28 @@ export default function ProductModal({ product, onClose }: ProductModalProps) {

Jenis Harga

- - +
@@ -178,19 +210,21 @@ export default function ProductModal({ product, onClose }: ProductModalProps) {

Jumlah

- + {quantity} - +

Stok tersedia: {maxStock}

@@ -205,14 +239,19 @@ export default function ProductModal({ product, onClose }: ProductModalProps) {
- {/* WhatsApp Order */} - + {/* Actions */} +
+ + +
diff --git a/resources/js/components/layout/app-header.tsx b/resources/js/components/layout/app-header.tsx index f4329e0..56954b8 100644 --- a/resources/js/components/layout/app-header.tsx +++ b/resources/js/components/layout/app-header.tsx @@ -141,7 +141,7 @@ export function AppHeader({ breadcrumbs = [] }: Props) {
- + k +
@@ -197,53 +226,49 @@ export default function Welcome({
{/* Left Column */}
-
- {homepage.hero_badge} -
+ + Hadir dengan Gaya Terbaru +

- {homepage.hero_title_line1}
- {homepage.hero_title_line2}{' '} + Nyaman
+ dalam setiap{' '} - {homepage.hero_title_highlight} + Penampilan

- {homepage.hero_description} + Koleksi fashion wanita dengan sentuhan elegan, material berkualitas, dan kenyamanan yang dapat Anda rasakan di setiap pemakaian.

- - {homepage.hero_cta_primary_text} - - - - {homepage.hero_cta_secondary_text} - + +
{/* Center Column: Visual */}
-
-
- {homepage.hero_bg_text_left} - {homepage.hero_bg_text_right} -
-
-
+
+
+ DST + Collection +
+
+
- #{homepage.scroll_hashtag} + #DSTCollection - {homepage.scroll_tagline} + Bahan Adem & Lembut
- +
@@ -317,47 +348,51 @@ export default function Welcome({
-

{homepage.catalog_badge}

-

{homepage.catalog_title}

-

{homepage.catalog_description}

+ + Katalog Eksklusif + +

Koleksi Busana Pilihan

+

Gunakan kategori dan filter di bawah untuk menyesuaikan pencarian busana idaman Anda dengan mudah.

{/* Filters */}
- handleSearchChange(e.target.value)} type="text" - placeholder={homepage.catalog_search_placeholder} - className="w-full bg-slate-50 border border-slate-200 text-xs px-4 py-3 pr-10 rounded-xl outline-none focus:border-amber-500 text-slate-700 transition-all" + 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" />
- + {categories.map((category) => ( - + ))}
@@ -384,6 +419,7 @@ export default function Welcome({ key={product.id} product={product} onQuickView={setActiveProduct} + contactPhone={contactPhone} /> ))}
@@ -394,12 +430,9 @@ export default function Welcome({

Mohon maaf, kami tidak menemukan pakaian yang cocok dengan kata kunci pencarian Anda.

- +
)} @@ -409,9 +442,11 @@ export default function Welcome({