mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
refactor(FE-62,65): enhance product quantity display and stock information in MovementForm
This commit is contained in:
@@ -266,6 +266,13 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
location?: string;
|
||||
}
|
||||
|
||||
interface ProductWarehouseOptionType extends OptionType {
|
||||
product_id: number;
|
||||
warehouse_id: number;
|
||||
warehouse_name: string;
|
||||
quantity: number;
|
||||
}
|
||||
|
||||
// Warehouse selection
|
||||
const [warehouseSelectInputValue, setWarehouseSelectInputValue] =
|
||||
useState('');
|
||||
@@ -304,8 +311,8 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
);
|
||||
const productWarehouseOptions = isResponseSuccess(productWarehouses)
|
||||
? productWarehouses?.data.map((pw) => ({
|
||||
value: pw.id,
|
||||
label: pw.product.name,
|
||||
value: pw.product.id,
|
||||
label: `${pw.product.name} - ${pw.warehouse.name} (Stock: ${pw.quantity.toLocaleString('id-ID')})`,
|
||||
product_id: pw.product.id,
|
||||
warehouse_id: pw.warehouse.id,
|
||||
warehouse_name: pw.warehouse.name,
|
||||
@@ -438,6 +445,33 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
[productWarehouseOptions, type]
|
||||
);
|
||||
|
||||
const getProductQtyAdornment = useCallback(
|
||||
(productIdx: number) => {
|
||||
if (type === 'detail') return null;
|
||||
const product = formik.values.products?.[productIdx];
|
||||
if (!product || !product.product_id) return null;
|
||||
|
||||
const availableStock = getAvailableStock(product.product_id);
|
||||
const requestedQty = Number(product.product_qty) || 0;
|
||||
const remainingStock = availableStock - requestedQty;
|
||||
|
||||
if (requestedQty > 0) {
|
||||
return (
|
||||
<span className='text-sm text-gray-600 whitespace-nowrap'>
|
||||
(sisa: {remainingStock.toLocaleString('id-ID')})
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<span className='text-sm text-gray-600 whitespace-nowrap'>
|
||||
(tersedia: {availableStock.toLocaleString('id-ID')})
|
||||
</span>
|
||||
);
|
||||
},
|
||||
[formik.values.products, getAvailableStock, type]
|
||||
);
|
||||
|
||||
const getProductQtyError = useCallback(
|
||||
(productIdx: number) => {
|
||||
if (type === 'detail') return null;
|
||||
@@ -813,7 +847,7 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
);
|
||||
formik.setFieldValue(
|
||||
`products.${idx}.product_id`,
|
||||
(val as OptionType)?.value
|
||||
(val as ProductWarehouseOptionType)?.value
|
||||
);
|
||||
}}
|
||||
options={productWarehouseOptions}
|
||||
@@ -837,46 +871,35 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<TextInput
|
||||
required
|
||||
type='number'
|
||||
name={`products.${idx}.product_qty`}
|
||||
value={product.product_qty ?? ''}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
isError={
|
||||
isRepeaterInputError(
|
||||
'products',
|
||||
'product_qty',
|
||||
idx
|
||||
).isError || Boolean(getProductQtyError(idx))
|
||||
}
|
||||
errorMessage={
|
||||
isRepeaterInputError(
|
||||
'products',
|
||||
'product_qty',
|
||||
idx
|
||||
).errorMessage ||
|
||||
getProductQtyError(idx) ||
|
||||
undefined
|
||||
}
|
||||
readOnly={type === 'detail'}
|
||||
className={{
|
||||
wrapper: 'w-full min-w-24',
|
||||
}}
|
||||
/>
|
||||
{type !== 'detail' && product.product_id && (
|
||||
<div className='text-sm text-gray-600'>
|
||||
<span className='font-semibold'>
|
||||
Stok tersedia:
|
||||
</span>{' '}
|
||||
{getAvailableStock(
|
||||
product.product_id
|
||||
).toLocaleString('id-ID')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<TextInput
|
||||
required
|
||||
type='number'
|
||||
name={`products.${idx}.product_qty`}
|
||||
value={product.product_qty ?? ''}
|
||||
onChange={formik.handleChange}
|
||||
onBlur={formik.handleBlur}
|
||||
endAdornment={getProductQtyAdornment(idx)}
|
||||
isError={
|
||||
isRepeaterInputError(
|
||||
'products',
|
||||
'product_qty',
|
||||
idx
|
||||
).isError || Boolean(getProductQtyError(idx))
|
||||
}
|
||||
errorMessage={
|
||||
isRepeaterInputError(
|
||||
'products',
|
||||
'product_qty',
|
||||
idx
|
||||
).errorMessage ||
|
||||
getProductQtyError(idx) ||
|
||||
undefined
|
||||
}
|
||||
readOnly={type === 'detail'}
|
||||
className={{
|
||||
wrapper: 'w-full min-w-48',
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
{type !== 'detail' && (
|
||||
<td>
|
||||
|
||||
Reference in New Issue
Block a user