feat(FE): Validate quantity against available stock

This commit is contained in:
rstubryan
2026-02-27 09:29:33 +07:00
parent 6f6f54571f
commit 9fb65bdacd
@@ -46,6 +46,7 @@ import {
TRANSACTION_SUBTYPE_OPTIONS,
} from '@/config/constant';
import NumberInput from '@/components/input/NumberInput';
import { formatNumber } from '@/lib/helper';
interface InventoryAdjustmentFormProps {
type?: 'add' | 'detail';
@@ -62,6 +63,7 @@ const InventoryAdjustmentForm = ({
setInventoryAdjustmentFormErrorMessage,
] = useState('');
const [quantityLabel, setQuantityLabel] = useState('Kuantitas');
const [quantityError, setQuantityError] = useState<string>('');
const [selectedLocation, setSelectedLocation] = useState<OptionType | null>(
null
@@ -211,6 +213,25 @@ const InventoryAdjustmentForm = ({
: [];
}, [productWarehouses]);
// Get available quantity from selected product
const selectedProductQuantity = useMemo(() => {
if (!selectedProduct) return 0;
const product = productOptions.find(
(opt) => opt.value === selectedProduct.value
);
return product?.quantity ?? 0;
}, [selectedProduct, productOptions]);
// Check if current transaction subtype reduces stock
const isStockOutSubtype = useMemo(() => {
const subtype = selectedTransactionSubtype?.value;
return (
subtype === 'RECORDING_STOCK_OUT' ||
subtype === 'RECORDING_DEPLETION_OUT' ||
subtype === 'MARKETING_OUT'
);
}, [selectedTransactionSubtype]);
const selectedProductFlags = useMemo(() => {
if (!selectedProduct) return [];
const product = productOptions.find(
@@ -372,6 +393,28 @@ const InventoryAdjustmentForm = ({
}
}, [selectedTransactionSubtype]);
// Validate quantity against available stock
useEffect(() => {
const qty = Number(formik.values.qty);
if (
isStockOutSubtype &&
selectedProduct &&
qty > 0 &&
qty > selectedProductQuantity
) {
setQuantityError(
`Kuantitas ${formatNumber(qty)} melebihi stok tersedia (${formatNumber(selectedProductQuantity)})`
);
} else {
setQuantityError('');
}
}, [
formik.values.qty,
isStockOutSubtype,
selectedProduct,
selectedProductQuantity,
]);
useEffect(() => {
if (selectedTransactionType?.value === 'RECORDING' && selectedProduct) {
setSelectedTransactionSubtype(null);
@@ -804,11 +847,18 @@ const InventoryAdjustmentForm = ({
value={formik.values.qty}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
isError={formik.touched.qty && Boolean(formik.errors.qty)}
errorMessage={formik.errors.qty as string}
isError={
(formik.touched.qty && Boolean(formik.errors.qty)) ||
Boolean(quantityError)
}
errorMessage={(formik.errors.qty as string) || quantityError}
readOnly={type === 'detail'}
bottomLabel={
selectedProduct
? `Kuantitas: ${formatNumber(selectedProductQuantity)}`
: undefined
}
/>
{/* Number Input Price */}
<NumberInput
required
@@ -856,7 +906,7 @@ const InventoryAdjustmentForm = ({
type='submit'
color='primary'
isLoading={formik.isSubmitting}
disabled={formik.isSubmitting}
disabled={formik.isSubmitting || Boolean(quantityError)}
className='px-4 w-full sm:w-auto'
>
Submit