feat: add category filter to product index page

This commit is contained in:
Yoga Pangestu 2026-06-14 02:54:06 +07:00
parent d27ac7ed6f
commit 67439af903
3 changed files with 20 additions and 3 deletions

View File

@ -29,13 +29,16 @@ public function index(Request $request): Response
{ {
$tableQuery = $this->parseDataTableQuery($request); $tableQuery = $this->parseDataTableQuery($request);
$isActive = $request->string('is_active')->toString(); $isActive = $request->string('is_active')->toString();
$categoryId = $request->string('category_id')->toString();
return Inertia::render('admin/master/products/Index', [ return Inertia::render('admin/master/products/Index', [
'products' => $this->productService->paginateForIndex($tableQuery, $isActive), 'products' => $this->productService->paginateForIndex($tableQuery, $isActive, $categoryId),
'outOfStockGroups' => $this->productService->outOfStockGroups(), 'outOfStockGroups' => $this->productService->outOfStockGroups(),
'stockWarningGroups' => $this->productService->stockWarningGroups(), 'stockWarningGroups' => $this->productService->stockWarningGroups(),
'categories' => $this->productService->categoryOptions(),
'filters' => $this->dataTableFilters($tableQuery, [ 'filters' => $this->dataTableFilters($tableQuery, [
'is_active' => $isActive, 'is_active' => $isActive,
'category_id' => $categoryId,
]), ]),
]); ]);
} }

View File

@ -113,7 +113,7 @@ private function inventoryAlertGroups(callable $filter): array
/** /**
* @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery * @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery
*/ */
public function paginateForIndex(array $tableQuery, string $isActive): LengthAwarePaginator public function paginateForIndex(array $tableQuery, string $isActive, string $categoryId = ''): LengthAwarePaginator
{ {
$query = Product::query() $query = Product::query()
->with([ ->with([
@ -135,6 +135,10 @@ public function paginateForIndex(array $tableQuery, string $isActive): LengthAwa
->when( ->when(
$isActive !== '', $isActive !== '',
fn (Builder $query) => $query->where('is_active', $isActive === '1') fn (Builder $query) => $query->where('is_active', $isActive === '1')
)
->when(
$categoryId !== '',
fn (Builder $query) => $query->whereHas('categories', fn (Builder $query) => $query->where('categories.id', $categoryId))
); );
$this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']); $this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']);

View File

@ -14,6 +14,7 @@ import {
import AdminLayout from '@/layouts/AdminLayout.vue'; import AdminLayout from '@/layouts/AdminLayout.vue';
import type { DataTableFilterDef } from '@/types/data-table'; import type { DataTableFilterDef } from '@/types/data-table';
import type { import type {
CategoryOption,
PaginatedProducts, PaginatedProducts,
ProductOutOfStockGroup, ProductOutOfStockGroup,
ProductStockWarningGroup, ProductStockWarningGroup,
@ -23,11 +24,13 @@ const props = defineProps<{
products: PaginatedProducts; products: PaginatedProducts;
outOfStockGroups: ProductOutOfStockGroup[]; outOfStockGroups: ProductOutOfStockGroup[];
stockWarningGroups: ProductStockWarningGroup[]; stockWarningGroups: ProductStockWarningGroup[];
categories: CategoryOption[];
filters: { filters: {
search: string; search: string;
sort?: string; sort?: string;
direction?: 'asc' | 'desc'; direction?: 'asc' | 'desc';
is_active?: string; is_active?: string;
category_id?: string;
}; };
}>(); }>();
@ -38,12 +41,18 @@ const { query, setSearch, setFilter, resetFilters, syncFromServer } =
useDataTableQuery({ useDataTableQuery({
url: '/admin/master/products', url: '/admin/master/products',
initial: { ...props.filters }, initial: { ...props.filters },
filterKeys: ['is_active'], filterKeys: ['is_active', 'category_id'],
}); });
useDataTableQuerySync(() => props.filters, syncFromServer); useDataTableQuerySync(() => props.filters, syncFromServer);
const filterDefs = computed<DataTableFilterDef[]>(() => [ const filterDefs = computed<DataTableFilterDef[]>(() => [
{
key: 'category_id',
label: 'Kategori',
type: 'select',
options: props.categories.map((c) => ({ value: String(c.value), label: c.label })),
},
{ {
key: 'is_active', key: 'is_active',
label: 'Status', label: 'Status',
@ -56,6 +65,7 @@ const filterDefs = computed<DataTableFilterDef[]>(() => [
]); ]);
const filterValues = computed(() => ({ const filterValues = computed(() => ({
category_id: query.value.category_id ?? '',
is_active: query.value.is_active ?? '', is_active: query.value.is_active ?? '',
})); }));