From ef987360f40281bc24f7ba50aa488cbfd0207d3b Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 12 Aug 2026 21:01:03 +0700 Subject: [PATCH] feat: enhance raw material filtering with name selection and add distinct name retrieval --- .../RawMaterial/RawMaterialController.php | 5 +- .../Master/RawMaterial/RawMaterialService.php | 9 ++++ .../pages/admin/master/raw-material/index.tsx | 49 +++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Admin/Master/RawMaterial/RawMaterialController.php b/app/Http/Controllers/Admin/Master/RawMaterial/RawMaterialController.php index b80ae9f..dbfbfb8 100644 --- a/app/Http/Controllers/Admin/Master/RawMaterial/RawMaterialController.php +++ b/app/Http/Controllers/Admin/Master/RawMaterial/RawMaterialController.php @@ -22,9 +22,10 @@ public function index(PaginatedRequest $request): Response return Inertia::render('admin/master/raw-material/index', [ 'rawMaterials' => $this->service->paginated( ...$request->validatedWithDefaults(), - filters: $request->only(['is_active', 'stock']), + filters: $request->only(['is_active', 'stock', 'name']), ), - 'filters' => $request->only(['is_active', 'stock']), + 'rawMaterialNames' => $this->service->getNames(), + 'filters' => $request->only(['is_active', 'stock', 'name']), ]); } diff --git a/app/Services/Admin/Master/RawMaterial/RawMaterialService.php b/app/Services/Admin/Master/RawMaterial/RawMaterialService.php index 4dbcae0..af8b89e 100644 --- a/app/Services/Admin/Master/RawMaterial/RawMaterialService.php +++ b/app/Services/Admin/Master/RawMaterial/RawMaterialService.php @@ -7,6 +7,7 @@ use App\Services\Concerns\RegistersMedia; use App\Services\S3PresignedService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\DB; class RawMaterialService @@ -17,6 +18,13 @@ public function __construct( private S3PresignedService $s3Service, ) {} + public function getNames(): Collection + { + return RawMaterial::select('name') + ->distinct() + ->pluck('name'); + } + public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator { $paginator = RawMaterial::query() @@ -25,6 +33,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort = 'rawMaterialPrices:id,raw_material_id,variant,price,stock', ]) ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) + ->when($filters['name'] ?? null, fn ($q, $name) => $q->where('name', 'like', "%{$name}%")) ->when(($filters['is_active'] ?? null) !== null && ($filters['is_active'] ?? null) !== '', function ($q) use ($filters) { $q->where('is_active', $filters['is_active'] === 'true'); }) diff --git a/resources/js/pages/admin/master/raw-material/index.tsx b/resources/js/pages/admin/master/raw-material/index.tsx index 786469e..a5ee762 100644 --- a/resources/js/pages/admin/master/raw-material/index.tsx +++ b/resources/js/pages/admin/master/raw-material/index.tsx @@ -1,12 +1,20 @@ import { Head, Link, router } from '@inertiajs/react'; import { Plus } from 'lucide-react'; -import { useState } from 'react'; +import { useMemo, useState } from 'react'; import { CardTable } from '@/components/data-display'; import { DeleteConfirmDialog } from '@/components/dialogs'; import { FilterPopover } from '@/components/data-display'; import { useCardTableExpand } from '@/components/hooks/use-card-table-expand'; import { PageHeader } from '@/components/layout'; import { Button } from '@/components/ui/button'; +import { + Combobox, + ComboboxContent, + ComboboxEmpty, + ComboboxInput, + ComboboxItem, + ComboboxList, +} from '@/components/ui/combobox'; import { Select, SelectContent, @@ -38,13 +46,15 @@ type Props = { per_page: number; total: number; }; + rawMaterialNames: string[]; filters: { is_active?: string; + name?: string; stock?: string; }; }; -export default function RawMaterialIndex({ rawMaterials, filters }: Props) { +export default function RawMaterialIndex({ rawMaterials, rawMaterialNames, filters }: Props) { const { can } = useCan(); const [deleting, setDeleting] = useState(null); const [deletingVariant, setDeletingVariant] = useState<{ @@ -76,6 +86,11 @@ export default function RawMaterialIndex({ rawMaterials, filters }: Props) { filterWithParams: false, }); + const sortedRawMaterialNames = useMemo( + () => [...rawMaterialNames].sort(), + [rawMaterialNames], + ); + function handleDelete() { if (!deleting) { return; @@ -107,9 +122,37 @@ export default function RawMaterialIndex({ rawMaterials, filters }: Props) { open={filterOpen} onOpenChange={setFilterOpen} filters={filters} - hasActiveFilters={Boolean(filters.is_active || filters.stock)} + hasActiveFilters={Boolean(filters.is_active || filters.name || filters.stock)} onClear={clearFilters} > +
+ + + applyFilter('name', (value as string) ?? '') + } + > + + + + Tidak ada bahan baku ditemukan. + + + {(name) => ( + {name} + )} + + + +
+