From 1b3dd34add0f3880b73a51487b870e9a03229819 Mon Sep 17 00:00:00 2001 From: rstubryan Date: Fri, 23 Jan 2026 13:21:12 +0700 Subject: [PATCH] refactor(FE): Filter products by available stock and format qty --- .../inventory/movement/form/MovementForm.tsx | 51 +++++++++++++------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/src/components/pages/inventory/movement/form/MovementForm.tsx b/src/components/pages/inventory/movement/form/MovementForm.tsx index 4d42efec..d944b19b 100644 --- a/src/components/pages/inventory/movement/form/MovementForm.tsx +++ b/src/components/pages/inventory/movement/form/MovementForm.tsx @@ -18,6 +18,7 @@ import { Movement, } from '@/types/api/inventory/movement'; import { isResponseError, isResponseSuccess } from '@/lib/api-helper'; +import { formatNumber } from '@/lib/helper'; import { useRouter } from 'next/navigation'; import { MovementFormSchema, @@ -740,12 +741,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { return ( formik.values.products ?.filter((p) => p.product) - .map((p) => ({ - value: p.product_id, - label: (p.product as OptionType)?.label, - })) ?? [] + .map((p) => { + const totalQtyUsed = + formik.values.deliveries?.reduce((total, d) => { + const productQty = d.products.reduce((sum, deliveryProduct) => { + if (deliveryProduct.product_id === p.product_id) { + return sum + (Number(deliveryProduct.product_qty) || 0); + } + return sum; + }, 0); + return total + productQty; + }, 0) || 0; + + const availableQty = Number(p.product_qty) - totalQtyUsed; + + if (availableQty > 0) { + return { + value: p.product_id, + label: (p.product as OptionType)?.label, + }; + } + + return null; + }) + .filter((option) => option !== null) ?? [] ); - }, [formik.values.products]); + }, [formik.values.products, formik.values.deliveries]); const getAvailableStock = useCallback( (productId: number) => { @@ -769,10 +790,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { const remainingStock = availableStock - requestedQty; if (requestedQty > 0) { - return `Sisa: ${remainingStock.toLocaleString('en-US')}`; + return `Sisa: ${formatNumber(remainingStock)}`; } - return `Tersedia: ${availableStock.toLocaleString('en-US')}`; + return `Tersedia: ${formatNumber(availableStock)}`; }, [formik.values.products, getAvailableStock, type] ); @@ -792,12 +813,9 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { if (!relatedProduct) return undefined; const totalQtyUsed = - formik.values.deliveries?.reduce((total, d, dIdx) => { - const productQty = d.products.reduce((sum, p, pIdx) => { - if ( - p.product_id === deliveryProduct.product_id && - !(dIdx === deliveryIdx && pIdx === productIdx) - ) { + formik.values.deliveries?.reduce((total, d) => { + const productQty = d.products.reduce((sum, p) => { + if (p.product_id === deliveryProduct.product_id) { return sum + (Number(p.product_qty) || 0); } return sum; @@ -806,7 +824,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { }, 0) || 0; const availableQty = Number(relatedProduct.product_qty) - totalQtyUsed; - return `Tersedia: ${availableQty.toLocaleString('en-US')}`; + + const displayQty = availableQty > 0 ? availableQty : 0; + + return `Tersedia: ${formatNumber(displayQty)}`; }, [formik.values.deliveries, formik.values.products, type] ); @@ -856,7 +877,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => { const requestedQty = Number(product.product_qty) || 0; if (requestedQty > availableStock) { - return `Qty melebihi stok tersedia! Maksimal: ${availableStock.toLocaleString('en-US')}`; + return `Qty melebihi stok tersedia! Maksimal: ${formatNumber(availableStock)}`; } return null;