'Produk', ])] class Index extends Component { use WithoutUrlPagination, WithPagination; public ?string $search = null; public ?string $sort = 'latest'; #[Url(as: 'type')] public string $productType = 'perfume'; #[Url(as: 'categories')] public array $selectedCategories = []; #[Url(as: 'price')] public ?string $priceRange = null; public array $availableCategories = []; public array $recommendations = []; public function mount(): void { $this->availableCategories = Category::perfume() ->orderBy('sort_order') ->pluck('name', 'id') ->toArray(); $this->recommendations = Perfume::with(['brand', 'categories', 'items']) ->withCount('items') ->orderBy('items_count', 'desc') ->take(8) ->get() ->map(function (Perfume $perfume) { $perfume->image = $perfume->getFirstMediaUrl('image') ?: asset('assets/images/dark-logo.png'); return $perfume; }) ->toArray(); } public function updatedSearch(): void { $this->resetPage(); } public function updatedSort(): void { $this->resetPage(); } public function updatedProductType(): void { $this->resetPage(); } public function updatedSelectedCategories(): void { $this->resetPage(); } public function updatedPriceRange(): void { $this->resetPage(); } public function render(): View { // Determine which model to query based on productType $query = match ($this->productType) { 'bottle' => Bottle::query(), 'arabian' => Product::query(), default => Perfume::with(['brand', 'categories']), // 'perfume' }; // Load items count for badge calculation $query->withCount([ 'items as total_sales' => function ($q) { $q->whereHas('order', function ($orderQuery) { $orderQuery->where('created_at', '>=', now()->subMonth()); }); }, ]); // Apply search filter $query->when($this->search, function (Builder $q) { $q->where('name', 'like', '%'.$this->search.'%'); }); // Apply category filter (only for perfumes) if ($this->productType === 'perfume' && $this->selectedCategories) { $query->whereHas('categories', function (Builder $q) { $q->whereIn('name', $this->selectedCategories); }); } // Apply price range filter $query->when($this->priceRange, function (Builder $q) { match ($this->priceRange) { '< 100k' => $q->where('sale_price', '<', 100000), '100k - 500k' => $q->whereBetween('sale_price', [100000, 500000]), '500k - 1jt' => $q->whereBetween('sale_price', [500000, 1000000]), '> 1jt' => $q->where('sale_price', '>', 1000000), default => null, }; }); // Apply sorting $query->when($this->sort, function (Builder $q) { match ($this->sort) { 'price_low' => $q->orderBy('sale_price', 'asc'), 'price_high' => $q->orderBy('sale_price', 'desc'), 'popular' => $q->withCount('items')->orderBy('items_count', 'desc'), default => $q->latest(), // 'latest' }; }, fn (Builder $q) => $q->latest()); // Paginate and transform results $products = $query->paginate(9)->through(function ($product) { $product->image = $product->getFirstMediaUrl('image') ?: asset('assets/images/dark-logo.png'); // Add categories for perfumes if not already loaded if ($this->productType === 'perfume' && ! $product->relationLoaded('categories')) { $product->load('categories'); } // Determine badge with priority $product->badge = $this->determineBadge($product); return $product; }); return view('livewire.home.product.index', [ 'pageTitle' => 'Produk', 'pageDesc' => 'Temukan aroma yang mencerminkan kepribadianmu! 🌸✨ Dari kemewahan parfum sampai botol eksklusif, semua ada di sini.', 'products' => $products, ]); } /** * Determine badge for product based on priority * Priority: 1. Baru, 2. Terlaris, 3. Hot */ private function determineBadge($product): ?array { // Priority 1: Terlaris (sales >= 500 in last month) if (isset($product->total_sales) && $product->total_sales >= 500) { return [ 'label' => 'Terlaris', 'class' => 'bg-red-500 text-white', ]; } // Priority 2: Baru (created within last month) if ($product->created_at && $product->created_at->isAfter(now()->subMonth())) { return [ 'label' => 'Baru', 'class' => 'bg-home-primary text-white', ]; } // Priority 3: Hot (high views - top 20% or > 100 views) if (isset($product->views) && $product->views > 100) { return [ 'label' => 'Hot', 'class' => 'bg-orange-500 text-white', ]; } return null; } }