From c4de085e111f4f3abcd41916ff2bc3a48a1b0d8e Mon Sep 17 00:00:00 2001 From: rstubryan Date: Sat, 18 Oct 2025 08:40:06 +0700 Subject: [PATCH] feat(FE-62,63): enhance warehouse stock information display in MovementForm --- .../inventory/movement/form/MovementForm.tsx | 82 +++++++++++++++---- 1 file changed, 65 insertions(+), 17 deletions(-) diff --git a/src/components/pages/inventory/movement/form/MovementForm.tsx b/src/components/pages/inventory/movement/form/MovementForm.tsx index d77f2de4..a35937f7 100644 --- a/src/components/pages/inventory/movement/form/MovementForm.tsx +++ b/src/components/pages/inventory/movement/form/MovementForm.tsx @@ -25,10 +25,7 @@ import { DeliverySchema, } from '@/components/pages/inventory/movement/form/MovementForm.schema'; import { useMovementFormHandlers } from './useMovementFormHandlers'; -import { - SupplierApi, - WarehouseApi, -} from '@/services/api/master-data'; +import { SupplierApi, WarehouseApi } from '@/services/api/master-data'; import { ProductWarehouseApi } from '@/services/api/inventory'; import { toast } from 'react-hot-toast'; import FileInput from '@/components/input/FileInput'; @@ -273,6 +270,36 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { quantity: number; } + const allProductWarehousesUrl = `${ProductWarehouseApi.basePath}`; + const { data: allProductWarehouses } = useSWR( + allProductWarehousesUrl, + ProductWarehouseApi.getAllFetcher + ); + + const warehouseStockMap = useMemo(() => { + if (!isResponseSuccess(allProductWarehouses)) return new Map(); + + const stockMap = new Map< + number, + { totalQty: number; productCount: number } + >(); + + allProductWarehouses.data.forEach((pw) => { + const warehouseId = pw.warehouse.id; + const existing = stockMap.get(warehouseId) || { + totalQty: 0, + productCount: 0, + }; + + stockMap.set(warehouseId, { + totalQty: existing.totalQty + pw.quantity, + productCount: existing.productCount + 1, + }); + }); + + return stockMap; + }, [allProductWarehouses]); + // Warehouse selection const [warehouseSelectInputValue, setWarehouseSelectInputValue] = useState(''); @@ -282,15 +309,22 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { WarehouseApi.getAllFetcher ); const warehouseOptions = isResponseSuccess(warehouses) - ? warehouses?.data.map((w) => ({ - value: w.id, - label: w.name, - area: w.area?.name, - location: - 'type' in w && (w.type === 'LOKASI' || w.type === 'KANDANG') - ? w.location?.name - : undefined, - })) + ? warehouses?.data.map((w) => { + const stockInfo = warehouseStockMap.get(w.id); + const stockLabel = stockInfo + ? ` (Stock: ${stockInfo.totalQty.toLocaleString('id-ID')} items, ${stockInfo.productCount} produk)` + : ' (Kosong)'; + + return { + value: w.id, + label: `${w.name}${stockLabel}`, + area: w.area?.name, + location: + 'type' in w && (w.type === 'LOKASI' || w.type === 'KANDANG') + ? w.location?.name + : undefined, + }; + }) : []; // Product Warehouse selection - Filter by source warehouse @@ -361,7 +395,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { const handleDeliveryCostPerItemChange = useCallback( (idx: number, value: string) => { const numValue = parseFloat(value) || 0; - formik.setFieldValue(`deliveries.${idx}.delivery_cost_per_item`, numValue); + formik.setFieldValue( + `deliveries.${idx}.delivery_cost_per_item`, + numValue + ); const delivery = formik.values.deliveries?.[idx]; if (delivery) { @@ -389,7 +426,11 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { ); // If delivery_cost is set, recalculate delivery_cost_per_item - if (delivery.delivery_cost && delivery.delivery_cost > 0 && productQty > 0) { + if ( + delivery.delivery_cost && + delivery.delivery_cost > 0 && + productQty > 0 + ) { const perItem = delivery.delivery_cost / productQty; if (Math.abs((delivery.delivery_cost_per_item || 0) - perItem) > 0.01) { formik.setFieldValue( @@ -410,7 +451,11 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { } } }); - }, [formik.values.deliveries?.map(d => d.products.reduce((sum, p) => sum + p.product_qty, 0)).join(',')]); + }, [ + formik.values.deliveries + ?.map((d) => d.products.reduce((sum, p) => sum + p.product_qty, 0)) + .join(','), + ]); useEffect(() => { if ( @@ -1147,7 +1192,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { name={`deliveries.${idx}.delivery_cost_per_item`} value={delivery.delivery_cost_per_item || ''} onChange={(e) => - handleDeliveryCostPerItemChange(idx, e.target.value) + handleDeliveryCostPerItemChange( + idx, + e.target.value + ) } onBlur={formik.handleBlur} {...isRepeaterInputError(