feat: enhance raw material filtering with name selection and add distinct name retrieval
This commit is contained in:
parent
d0482c03db
commit
ef987360f4
@ -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']),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@ -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');
|
||||
})
|
||||
|
||||
@ -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<RawMaterial | null>(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}
|
||||
>
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-xs text-muted-foreground">
|
||||
Nama Bahan Baku
|
||||
</label>
|
||||
<Combobox
|
||||
items={sortedRawMaterialNames}
|
||||
value={filters.name ?? ''}
|
||||
onValueChange={(value) =>
|
||||
applyFilter('name', (value as string) ?? '')
|
||||
}
|
||||
>
|
||||
<ComboboxInput
|
||||
placeholder="Pilih bahan baku..."
|
||||
className="w-full"
|
||||
/>
|
||||
<ComboboxContent>
|
||||
<ComboboxEmpty>
|
||||
Tidak ada bahan baku ditemukan.
|
||||
</ComboboxEmpty>
|
||||
<ComboboxList>
|
||||
{(name) => (
|
||||
<ComboboxItem key={name} value={name}>{name}</ComboboxItem>
|
||||
)}
|
||||
</ComboboxList>
|
||||
</ComboboxContent>
|
||||
</Combobox>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="text-xs text-muted-foreground">Status</label>
|
||||
<Select
|
||||
|
||||
Loading…
Reference in New Issue
Block a user