mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
feat(FE-62): enhance MovementForm with delivery product input error handling and validation
This commit is contained in:
@@ -214,6 +214,32 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isDeliveryProductInputError = (
|
||||||
|
deliveryIdx: number,
|
||||||
|
productIdx: number,
|
||||||
|
column: keyof DeliverySchema['products'][number]
|
||||||
|
) => {
|
||||||
|
const touchedDelivery = formik.touched.deliveries?.[deliveryIdx];
|
||||||
|
const errorDelivery = formik.errors.deliveries?.[deliveryIdx] as
|
||||||
|
| { products: Array<Record<string, string>> }
|
||||||
|
| undefined;
|
||||||
|
|
||||||
|
if (!touchedDelivery?.products || !errorDelivery?.products) {
|
||||||
|
return {
|
||||||
|
isError: false,
|
||||||
|
errorMessage: undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const touchedField = touchedDelivery.products[productIdx]?.[column];
|
||||||
|
const errorField = errorDelivery.products[productIdx]?.[column];
|
||||||
|
|
||||||
|
return {
|
||||||
|
isError: Boolean(touchedField && errorField),
|
||||||
|
errorMessage: touchedField ? errorField : undefined,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
interface WarehouseOptionType extends OptionType {
|
interface WarehouseOptionType extends OptionType {
|
||||||
area?: string;
|
area?: string;
|
||||||
location?: string;
|
location?: string;
|
||||||
@@ -305,11 +331,11 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
if (!relatedProduct) return true;
|
if (!relatedProduct) return true;
|
||||||
|
|
||||||
const totalQtyUsed =
|
const totalQtyUsed =
|
||||||
formik.values.deliveries?.reduce((total, d) => {
|
formik.values.deliveries?.reduce((total, d, dIdx) => {
|
||||||
const productQty = d.products.reduce((sum, p, pIdx) => {
|
const productQty = d.products.reduce((sum, p, pIdx) => {
|
||||||
if (
|
if (
|
||||||
p.product_id === productId &&
|
p.product_id === productId &&
|
||||||
!(d === delivery && pIdx === deliveryProductIdx)
|
!(dIdx === deliveryIdx && pIdx === deliveryProductIdx)
|
||||||
) {
|
) {
|
||||||
return sum + (Number(p.product_qty) || 0);
|
return sum + (Number(p.product_qty) || 0);
|
||||||
}
|
}
|
||||||
@@ -323,6 +349,47 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
[formik.values.deliveries, formik.values.products]
|
[formik.values.deliveries, formik.values.products]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const getDeliveryQtyError = useCallback(
|
||||||
|
(deliveryIdx: number, deliveryProductIdx: number) => {
|
||||||
|
const delivery = formik.values.deliveries?.[deliveryIdx];
|
||||||
|
if (!delivery) return null;
|
||||||
|
|
||||||
|
const deliveryProduct = delivery.products[deliveryProductIdx];
|
||||||
|
if (!deliveryProduct || !deliveryProduct.product_id) return null;
|
||||||
|
|
||||||
|
const qty = Number(deliveryProduct.product_qty) || 0;
|
||||||
|
const productId = deliveryProduct.product_id;
|
||||||
|
|
||||||
|
const relatedProduct = formik.values.products?.find(
|
||||||
|
(p) => p.product_id === productId
|
||||||
|
);
|
||||||
|
if (!relatedProduct) return null;
|
||||||
|
|
||||||
|
const totalQtyUsed =
|
||||||
|
formik.values.deliveries?.reduce((total, d, dIdx) => {
|
||||||
|
const productQty = d.products.reduce((sum, p, pIdx) => {
|
||||||
|
if (
|
||||||
|
p.product_id === productId &&
|
||||||
|
!(dIdx === deliveryIdx && pIdx === deliveryProductIdx)
|
||||||
|
) {
|
||||||
|
return sum + (Number(p.product_qty) || 0);
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}, 0);
|
||||||
|
return total + productQty;
|
||||||
|
}, 0) || 0;
|
||||||
|
|
||||||
|
const availableQty = Number(relatedProduct.product_qty) - totalQtyUsed;
|
||||||
|
|
||||||
|
if (totalQtyUsed + qty > Number(relatedProduct.product_qty)) {
|
||||||
|
return `Qty melebihi stok produk! Tersedia: ${availableQty}, Total digunakan: ${totalQtyUsed + qty}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
[formik.values.deliveries, formik.values.products]
|
||||||
|
);
|
||||||
|
|
||||||
const invalidQtyRows = useMemo(
|
const invalidQtyRows = useMemo(
|
||||||
() =>
|
() =>
|
||||||
formik.values.deliveries?.flatMap((delivery, deliveryIdx) =>
|
formik.values.deliveries?.flatMap((delivery, deliveryIdx) =>
|
||||||
@@ -334,7 +401,10 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
[formik.values.deliveries, formik.values.products, validateDeliveryQty]
|
[formik.values.deliveries, formik.values.products, validateDeliveryQty]
|
||||||
);
|
);
|
||||||
|
|
||||||
const hasInvalidQty = invalidQtyRows.some(Boolean);
|
const hasInvalidQty = useMemo(
|
||||||
|
() => invalidQtyRows.some(Boolean),
|
||||||
|
[invalidQtyRows]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -762,6 +832,16 @@ const MovementForm = ({ type = 'add', initialValues }: MovementFormProps) => {
|
|||||||
value={delivery.products[0]?.product_qty ?? ''}
|
value={delivery.products[0]?.product_qty ?? ''}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
onBlur={formik.handleBlur}
|
onBlur={formik.handleBlur}
|
||||||
|
isError={
|
||||||
|
isDeliveryProductInputError(idx, 0, 'product_qty')
|
||||||
|
.isError || Boolean(getDeliveryQtyError(idx, 0))
|
||||||
|
}
|
||||||
|
errorMessage={
|
||||||
|
isDeliveryProductInputError(idx, 0, 'product_qty')
|
||||||
|
.errorMessage ||
|
||||||
|
getDeliveryQtyError(idx, 0) ||
|
||||||
|
undefined
|
||||||
|
}
|
||||||
readOnly={type === 'detail'}
|
readOnly={type === 'detail'}
|
||||||
className={{
|
className={{
|
||||||
wrapper: 'w-full min-w-24',
|
wrapper: 'w-full min-w-24',
|
||||||
|
|||||||
Reference in New Issue
Block a user