parfum/app/Livewire/Home/Product/Index.php

192 lines
5.8 KiB
PHP

<?php
namespace App\Livewire\Home\Product;
use App\Models\Bottle;
use App\Models\Category;
use App\Models\Perfume;
use App\Models\Product;
use Illuminate\Contracts\View\View;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Attributes\Layout;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithoutUrlPagination;
use Livewire\WithPagination;
#[Layout('components.layouts.home', [
'title' => '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;
}
}