diff --git a/resources/js/pages/admin/manage/cutting/create.tsx b/resources/js/pages/admin/manage/cutting/create.tsx index 7bd132e..995a4f3 100644 --- a/resources/js/pages/admin/manage/cutting/create.tsx +++ b/resources/js/pages/admin/manage/cutting/create.tsx @@ -1,7 +1,7 @@ 'use no memo'; import { Form, Head, Link, usePage } from '@inertiajs/react'; -import { ArrowLeft, Check, Layers, Plus, ShoppingCart, Trash2 } from 'lucide-react'; +import { ArrowLeft, Check, Layers, Plus, Search, ShoppingCart, Trash2 } from 'lucide-react'; import { useCallback, useMemo, useRef, useState } from 'react'; import { toast } from 'sonner'; import { ConfirmDialog } from '@/components/dialogs'; @@ -76,6 +76,7 @@ export default function CuttingCreate({ rawMaterials }: Props) { return []; }); const [selectedMaterialName, setSelectedMaterialName] = useState(draft?.selectedMaterialName ?? ''); + const [variantSearch, setVariantSearch] = useState(''); const [productName, setProductName] = useState(draft?.productName ?? ''); const [sample, setSample] = useState(draft?.sample ?? 0); @@ -149,13 +150,22 @@ export default function CuttingCreate({ rawMaterials }: Props) { [rawMaterials, selectedMaterialName], ); - const addVariant = useCallback( - (priceId: number) => { - if (!selectedMaterial) { - return; - } + const groupedVariants = useMemo(() => { + if (!variantSearch) return []; + const search = variantSearch.toLowerCase(); + return rawMaterials + .map((rm) => ({ + ...rm, + raw_material_prices: rm.raw_material_prices.filter( + (p) => p.variant.toLowerCase().includes(search), + ), + })) + .filter((rm) => rm.raw_material_prices.length > 0); + }, [rawMaterials, variantSearch]); - const price = selectedMaterial.raw_material_prices.find((p) => p.id === priceId); + const addVariant = useCallback( + (rawMaterial: (typeof rawMaterials)[number], priceId: number) => { + const price = rawMaterial.raw_material_prices.find((p) => p.id === priceId); if (!price) { return; @@ -174,14 +184,14 @@ export default function CuttingCreate({ rawMaterials }: Props) { material_result: 0, combination_id: null, variant: price.variant, - material_name: selectedMaterial.name, - unit: selectedMaterial.unit, + material_name: rawMaterial.name, + unit: rawMaterial.unit, photo_url: price.photo_url, }, ]; }); }, - [selectedMaterial], + [], ); const openComboDialog = useCallback((materialName: string, preSelectPriceId?: number) => { @@ -352,9 +362,70 @@ export default function CuttingCreate({ rawMaterials }: Props) { - {selectedMaterial && selectedMaterial.raw_material_prices.length > 0 && ( +
+ +
+ + setVariantSearch(e.target.value)} + className="pl-8" + /> +
+
+ + {variantSearch && groupedVariants.length > 0 && ( +
+ {groupedVariants.map((rm) => ( +
+

{rm.name} ({rm.unit})

+
+ {rm.raw_material_prices.map((price) => { + const isAdded = materials.some((m) => m.raw_material_price_id === price.id); + const addedCount = materials.filter((m) => m.raw_material_price_id === price.id).length; + + return ( +
+
+ {price.photo_url ? ( + {price.variant} + ) : ( +
N/A
+ )} +
+

{price.variant}

+

+ Stok: {formatNumber(Number(price.stock))} {rm.unit} · {formatCurrency(price.price)} + {addedCount > 0 && ` · ×${addedCount}`} +

+
+
+
+ + +
+
+ ); + })} +
+
+ ))} +
+ )} + + {variantSearch && groupedVariants.length === 0 && ( +

Tidak ada varian ditemukan.

+ )} + + {!variantSearch && selectedMaterial && selectedMaterial.raw_material_prices.length > 0 && (
-
{selectedMaterial.raw_material_prices.map((price) => { const isAdded = materials.some((m) => m.raw_material_price_id === price.id); @@ -377,7 +448,7 @@ export default function CuttingCreate({ rawMaterials }: Props) {
- diff --git a/resources/js/pages/admin/manage/cutting/edit.tsx b/resources/js/pages/admin/manage/cutting/edit.tsx index 7bb1a63..87a941d 100644 --- a/resources/js/pages/admin/manage/cutting/edit.tsx +++ b/resources/js/pages/admin/manage/cutting/edit.tsx @@ -1,7 +1,7 @@ 'use no memo'; import { Form, Head, Link, usePage } from '@inertiajs/react'; -import { ArrowLeft, Check, Layers, Plus, ShoppingCart, Trash2 } from 'lucide-react'; +import { ArrowLeft, Check, Layers, Plus, Search, ShoppingCart, Trash2 } from 'lucide-react'; import { useCallback, useMemo, useRef, useState } from 'react'; import { toast } from 'sonner'; import { ConfirmDialog } from '@/components/dialogs'; @@ -86,6 +86,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { ); const [selectedMaterialName, setSelectedMaterialName] = useState(''); + const [variantSearch, setVariantSearch] = useState(''); const [productName, setProductName] = useState(cutting.product_name); const [sample, setSample] = useState(cutting.sample); @@ -130,13 +131,22 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { [rawMaterials, selectedMaterialName], ); - const addVariant = useCallback( - (priceId: number) => { - if (!selectedMaterial) { - return; - } + const groupedVariants = useMemo(() => { + if (!variantSearch) return []; + const search = variantSearch.toLowerCase(); + return rawMaterials + .map((rm) => ({ + ...rm, + raw_material_prices: rm.raw_material_prices.filter( + (p) => p.variant.toLowerCase().includes(search), + ), + })) + .filter((rm) => rm.raw_material_prices.length > 0); + }, [rawMaterials, variantSearch]); - const price = selectedMaterial.raw_material_prices.find((p) => p.id === priceId); + const addVariant = useCallback( + (rawMaterial: (typeof rawMaterials)[number], priceId: number) => { + const price = rawMaterial.raw_material_prices.find((p) => p.id === priceId); if (!price) { return; @@ -155,14 +165,14 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) { material_result: 0, combination_id: null, variant: price.variant, - material_name: selectedMaterial.name, - unit: selectedMaterial.unit, + material_name: rawMaterial.name, + unit: rawMaterial.unit, photo_url: price.photo_url, }, ]; }); }, - [selectedMaterial], + [], ); const openComboDialog = useCallback((materialName: string, preSelectPriceId?: number) => { @@ -328,9 +338,70 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) {
- {selectedMaterial && selectedMaterial.raw_material_prices.length > 0 && ( +
+ +
+ + setVariantSearch(e.target.value)} + className="pl-8" + /> +
+
+ + {variantSearch && groupedVariants.length > 0 && ( +
+ {groupedVariants.map((rm) => ( +
+

{rm.name} ({rm.unit})

+
+ {rm.raw_material_prices.map((price) => { + const isAdded = materials.some((m) => m.raw_material_price_id === price.id); + const addedCount = materials.filter((m) => m.raw_material_price_id === price.id).length; + + return ( +
+
+ {price.photo_url ? ( + {price.variant} + ) : ( +
N/A
+ )} +
+

{price.variant}

+

+ Stok: {formatNumber(Number(price.stock))} {rm.unit} · {formatCurrency(price.price)} + {addedCount > 0 && ` · ×${addedCount}`} +

+
+
+
+ + +
+
+ ); + })} +
+
+ ))} +
+ )} + + {variantSearch && groupedVariants.length === 0 && ( +

Tidak ada varian ditemukan.

+ )} + + {!variantSearch && selectedMaterial && selectedMaterial.raw_material_prices.length > 0 && (
-
{selectedMaterial.raw_material_prices.map((price) => { const isAdded = materials.some((m) => m.raw_material_price_id === price.id); @@ -353,7 +424,7 @@ export default function CuttingEdit({ cutting, rawMaterials }: Props) {
-