From b45052dc558ed22a5e41dcf16f6bb4633793e689 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 6 Aug 2026 10:14:49 +0700 Subject: [PATCH] feat: refactor CuttingItemSubRow to improve material grouping and display logic --- .../admin/manage/cutting/cutting-card.tsx | 10 +- .../admin/manage/cutting/cutting-sub-row.tsx | 314 ++++++++++++------ 2 files changed, 223 insertions(+), 101 deletions(-) diff --git a/resources/js/pages/admin/manage/cutting/cutting-card.tsx b/resources/js/pages/admin/manage/cutting/cutting-card.tsx index f496aea..c9da019 100644 --- a/resources/js/pages/admin/manage/cutting/cutting-card.tsx +++ b/resources/js/pages/admin/manage/cutting/cutting-card.tsx @@ -28,7 +28,15 @@ export function CuttingCardRow({ const { can } = useCan(); const items = cutting.cutting_materials ?? []; const result = cutting.cutting_results?.[0]; - const materialCount = items.length; + const singleCount = items.filter( + (item) => item.combination_id === null, + ).length; + const comboCount = new Set( + items + .filter((item) => item.combination_id !== null) + .map((item) => item.combination_id), + ).size; + const materialCount = singleCount + comboCount; const productName = result?.product_name ?? '-'; const totalUsage = items.reduce( (sum, item) => sum + Number(item.material_usage), diff --git a/resources/js/pages/admin/manage/cutting/cutting-sub-row.tsx b/resources/js/pages/admin/manage/cutting/cutting-sub-row.tsx index 11d3f71..f64cd63 100644 --- a/resources/js/pages/admin/manage/cutting/cutting-sub-row.tsx +++ b/resources/js/pages/admin/manage/cutting/cutting-sub-row.tsx @@ -8,124 +8,238 @@ import { TableRow, } from '@/components/ui/table'; import { formatNumber } from '@/lib/format'; +import { Fragment } from 'react'; import type { Cutting } from './columns'; export function CuttingItemSubRow({ cutting }: { cutting: Cutting }) { const items = cutting.cutting_materials ?? []; const combinations = cutting.cutting_material_combinations ?? []; - const groupedMaterials = items.reduce( + const singles = items.filter((item) => item.combination_id === null); + const comboItems = items.filter((item) => item.combination_id !== null); + + const comboGroups: Record = {}; + comboItems.forEach((item) => { + const comboId = item.combination_id!; + if (!comboGroups[comboId]) comboGroups[comboId] = []; + comboGroups[comboId].push(item); + }); + + const singleByRawMaterial = singles.reduce( (acc, item) => { - const key = item.combination_id ?? `single-${item.id}`; - - if (!acc[key]) { - acc[key] = { - combination: item.combination_id - ? (combinations.find((c) => c.id === item.combination_id) ?? null) - : null, - materials: [], - }; - } - - acc[key].materials.push(item); - + const name = + item.raw_material_price?.raw_material?.name ?? 'BING'; + if (!acc[name]) acc[name] = []; + acc[name].push(item); return acc; }, - {} as Record< - string, - { - combination: { id: number; material_result: number | null } | null; - materials: typeof items; - } - >, + {} as Record, ); + const hasSingle = singles.length > 0; + const hasCombo = comboItems.length > 0; + + let counter = 0; + return ( -
- {Object.entries(groupedMaterials).map(([key, group]) => ( -
- {group.combination && ( -
- - Kombinasi - - {group.combination.material_result !== null && ( - - Hasil: {formatNumber(group.combination.material_result)} - +
+ + + + + No + + Foto + Varian + + Pemakaian + + Hasil + + + + {hasSingle && ( + <> + + + Single + + + {Object.entries(singleByRawMaterial).map( + ([rawMaterialName, groupItems]) => ( + + + + {rawMaterialName} + + + {groupItems.map((item) => { + counter++; + return ( + + + {counter} + + + {item.raw_material_price + ?.photo_url ? ( + + ) : ( +
+ N/A +
+ )} +
+ + {item.raw_material_price + ?.variant ?? '-'} + + + {formatNumber( + item.material_usage, + )} + + + {item.material_result !== + null + ? formatNumber( + item.material_result, + ) + : '-'} + +
+ ); + })} +
+ ), )} - + )} -
- + {hasCombo && ( + <> - - No - - Foto - Bahan Baku - Varian - Pemakaian - Hasil + + Kombinasi + - - - {group.materials.length === 0 ? ( - - - Tidak ada item. - - - ) : ( - group.materials.map((item, index) => ( - - - {index + 1} - - - {item.raw_material_price?.photo_url ? ( - - ) : ( -
- N/A -
- )} -
- - {item.raw_material_price?.raw_material?.name ?? '-'} - - - {item.raw_material_price?.variant ?? '-'} - - - {formatNumber(item.material_usage)} - - - {group.combination - ? '-' - : (item.material_result !== null - ? formatNumber(item.material_result) - : '-')} - -
- )) + {Object.entries(comboGroups).map( + ([comboId, materials]) => { + counter++; + const combo = combinations.find( + (c) => c.id === Number(comboId), + ); + + return ( + + + + {counter} + + + Kombinasi{' '} + {counter} + {combo?.material_result !== + null && + combo?.material_result !== + undefined && ( + + (Hasil:{' '} + {formatNumber( + combo.material_result, + )} + ) + + )} + + + {materials.map((item) => ( + + + + {item + .raw_material_price + ?.photo_url ? ( + + ) : ( +
+ N/A +
+ )} +
+ + {item + .raw_material_price + ?.raw_material + ?.name ?? '-'}{' '} + -{' '} + {item + .raw_material_price + ?.variant ?? '-'} + + + {formatNumber( + item.material_usage, + )} + + + - + +
+ ))} +
+ ); + }, )} -
-
-
- ))} + + )} + + {items.length === 0 && ( + + + Tidak ada bahan baku. + + + )} + +
); }